M2.875 · Deep Learning · PEC1

2022-2 · Máster universitario en Ciencia de datos (Data science)

Estudios de Informática, Multimedia y Telecomunicación

 

PEC 1: Redes neuronales artificiales y convolucionales con Keras¶

A lo largo de esta práctica vamos a implementar varios modelos de redes neuronales para clasificar las imágenes de una base de datos de imágenes satelitales. En concreto:

  • Se implementará una red completamente conectada para establecer un modelo de referencia o baseline
  • Se implementará una red convolucional
  • Se implementará un autoencoder
  • Se implementará una red convolucional profunda a partir de un modelo conocido (VGG16) pre-entrenado en Imagenet utilizando transfer-learning

Consideraciones generales:

  • La solución planteada no puede utilizar métodos, funciones o parámetros declarados deprecated en futuras versiones, a excepción de la carga de datos cómo se indica posteriormente.
  • Esta PEC debe realizarse de forma estrictamente individual. Cualquier indicio de copia será penalizado con un suspenso (D) para todas las partes implicadas y la posible evaluación negativa de la asignatura de forma íntegra.
  • Es necesario que el estudiante indique todas las fuentes que ha utilizado para la realización de la PEC. De no ser así, se considerará que el estudiante ha cometido plagio, siendo penalizado con un suspenso (D) y la posible evaluación negativa de la asignatura de forma íntegra.

Formato de la entrega:

  • Algunos ejercicios pueden suponer varios minutos de ejecución, por lo que la entrega debe hacerse en formato notebook y en formato html, donde se vea el código, los resultados y comentarios de cada ejercicio. Se puede exportar el notebook a HTML desde el menú File $\to$ Download as $\to$ HTML.
  • Existe un tipo de celda especial para albergar texto. Este tipo de celda os será muy útil para responder a las diferentes preguntas teóricas planteadas a lo largo de la actividad. Para cambiar el tipo de celda a este tipo, en el menú: Cell $\to$ Cell Type $\to$ Markdown.

0. Contexto y carga de librerías¶

Las imágenes tomadas por satélite son clave en la supervisión del uso y la cobertura del suelo, cuestiones relevantes para la gestión ambiental, la planificación urbana, la sostenibilidad y para combatir el cambio climático.

En esta práctica, trabajaremos con la base de datos UC Merced Land Use Data, que consiste en imágenes satelitales de 256x256 píxeles de 21 escenas diferentes: las clases son diversas, conteniendo escenas e imágenes de aviones o ríos, entre otras categorías.

Concretamente trabajaremos con una versión aumentada de dicha base de datos que está disponible en un repositorio de Kaggle. En esta versión se han llevado a cabo varios procesos de aumentación de datos de tal forma que el número de imágenes por clase pasa de 100 a 500.

Nota: Se recomienda realizar la práctica en el entorno que ofrece la plataforma Kaggle, ya que ofrece un entorno gratuito con 30 horas semanales de uso de GPU.

A lo largo de toda la práctica, para la creación de las distintas redes, iremos alternando el uso del modelo Sequential y el modelo Functional de Keras a través de las clases Sequential y Model respectivamente.

Empezamos cargando las librerías mas relevantes:

In [2]:
# Importamos tensorflow
import tensorflow as tf
print("TF version   : ", tf.__version__)

# Necesitaremos GPU
print("GPU available: ", tf.config.list_physical_devices('GPU'))

# keras version is 2.11.0
import keras
print("Keras version   : ", keras.__version__)
TF version   :  2.11.0
GPU available:  [PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]
Keras version   :  2.11.0
In [3]:
# Importamos los elementos de keras que utilizaremos con mayor frecuencia
from keras.utils import image_dataset_from_directory
from keras.layers import (
    GlobalAveragePooling2D, Flatten, Input,
    Dense, Dropout, Conv2D, Conv2DTranspose, BatchNormalization, 
    MaxPooling2D, UpSampling2D, Rescaling, Resizing)
from keras.callbacks import EarlyStopping
from keras.optimizers import Adam
from keras import Sequential, Model
from tensorflow.keras import layers
In [4]:
# Importamos el resto de librerías que necesitaremos para la PEC
import cv2
import glob
import os
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import time

1. Descarga, análisis y pre-procesado de los datos (1,5 puntos)¶

En este apartado exploraremos la base de datos y prepararemos la carga de las imágenes para los modelos de los siguientes apartados.

Para la descarga de la base de datos tenemos 2 opciones dependiendo de si decidimos trabajar en local o desde el entorno de Kaggle:

  • Si trabajamos en local debemos descargar la base de datos desde el siguiente enlace (es un archivo .zip que ocupa 2 GB) y descomprimirlo.
  • Si trabajamos desde Kaggle. Debemos subir el Notebook del enunciado a la plataforma (para ello podéis seguir los 6 primeros pasos del siguiente artículo) y después, una vez subido el notebook, clickar el botón '+ Add Data' y en la caja de búsqueda introducir la dirección 'https://www.kaggle.com/datasets/apollo2506/landuse-scene-classification'. Una vez encontrado el dataset darle al botón '+' (Add Dataset), y desde ese momento ya tendréis accesible la base de datos en la ruta ../input/.

Una vez tenemos la base de datos accesible vamos a inspeccionarla.

Las imágenes se encuentran agrupadas de 2 formas diferentes:

  • En la carpeta /landuse-scene-classification/images/ se encuentra el total de las imágenes separadas por clases (cada clase en una carpeta distinta). Pero no se ha realizado una separación en conjunto de entrenamiento y test (o entrenamiento, validación y test).
  • En la carpeta /landuse-scene-classification/images_train_test_val/ se encuentran 3 carpetas (test, train y validation) en las que el total de imágenes se ha separado de forma aleatoria. En cada una de las 3 carpetas, tenemos imágenes de las 21 clases agrupadas en sus correspondientes carpetas. En la carpeta raíz /landuse-scene-classification/ tenemos 3 archivos .csv con la distribución de cada carpeta.

En esta práctica utilizaremos el dataset ya particionado, es decir, trabajaremos con las imágenes que se encuentran en la ruta /landuse-scene-classification/images_train_test_val/.

1.1. Análisis de los archivos .csv¶

A partir de los archivos .csv podemos ver cómo se han distribuído los datos. Por ejemplo:

In [29]:
train = pd.read_csv('../input/landuse-scene-classification/train.csv')
train.head(5)
Out[29]:
Unnamed: 0 Filename Label ClassName
0 5818 runway/runway_000259.png 16 runway
1 1327 intersection/intersection_000348.png 10 intersection
2 2529 agricultural/agricultural_000025.png 0 agricultural
3 3865 chaparral/chaparral_000195.png 5 chaparral
4 2024 airplane/airplane_000260.png 1 airplane
In [30]:
test = pd.read_csv('../input/landuse-scene-classification/test.csv')
test.head(5)
Out[30]:
Unnamed: 0 Filename Label ClassName
0 311 river/river_000149.png 15 river
1 975 mediumresidential/mediumresidential_000335.png 11 mediumresidential
2 547 overpass/overpass_000338.png 13 overpass
3 670 storagetanks/storagetanks_000307.png 18 storagetanks
4 330 river/river_000370.png 15 river
In [31]:
validation = pd.read_csv('../input/landuse-scene-classification/validation.csv')
validation.head(5)
Out[31]:
Unnamed: 0 Filename Label ClassName
0 1928 mediumresidential/mediumresidential_000305.png 11 mediumresidential
1 102 buildings/buildings_000191.png 4 buildings
2 823 tenniscourt/tenniscourt_000224.png 19 tenniscourt
3 2083 denseresidential/denseresidential_000436.png 6 denseresidential
4 1579 baseballdiamond/baseballdiamond_000280.png 2 baseballdiamond
Ejercicio [0,5 pts.]: A partir de los 3 archivos .csv se pide:
  • Extraer los nombres de las 21 clases (esto sólo hace falta hacerlo en uno de los 3 archivos)
  • ¿Cuántas instancias tenemos en total para cada conjunto de datos?
  • Comprobar que las clases están balanceadas en los 3 conjuntos de datos (contando para cada conjunto, cuantas instancias/ejemplos tenemos para cada clase)
In [32]:
# Extraer nombres de las clases
nombres = train['ClassName'].unique()
print(nombres)
['runway' 'intersection' 'agricultural' 'chaparral' 'airplane'
 'storagetanks' 'tenniscourt' 'overpass' 'harbor' 'buildings'
 'mediumresidential' 'baseballdiamond' 'golfcourse' 'freeway'
 'sparseresidential' 'river' 'mobilehomepark' 'forest' 'beach'
 'parkinglot' 'denseresidential']
In [33]:
# Número de instancias por conjunto
conteo_instancias_train = train.shape[0]
conteo_instancias_test  = test.shape[0]
conteo_instancias_validation = validation.shape[0]
print("\n\n=======\nTRAIN\n=======\n" ,conteo_instancias_train)
print("\n\n=====\nTEST\n=====\n",conteo_instancias_test)
print("\n\n==========\nVALIDATION\n==========\n",conteo_instancias_validation)

=======
TRAIN
=======
 7350


=====
TEST
=====
 1050


==========
VALIDATION
==========
 2100
In [34]:
# Número de instancias por clase
conteo_instancias_Clase_train = train['ClassName'].value_counts()
conteo_instancias_Clase_test  = test['ClassName'].value_counts()
conteo_instancias_Clase_validation = validation['ClassName'].value_counts()
print("\n\n==========================\nTRAIN\n==========================\n" ,conteo_instancias_Clase_train)
print("\n\n==========================\nTEST\n==========================\n",conteo_instancias_Clase_test)
print("\n\n==========================\nVALIDATION\n==========================\n",conteo_instancias_Clase_validation)

==========================
TRAIN
==========================
 runway               350
baseballdiamond      350
parkinglot           350
beach                350
forest               350
mobilehomepark       350
river                350
sparseresidential    350
freeway              350
golfcourse           350
mediumresidential    350
intersection         350
buildings            350
harbor               350
overpass             350
tenniscourt          350
storagetanks         350
airplane             350
chaparral            350
agricultural         350
denseresidential     350
Name: ClassName, dtype: int64


==========================
TEST
==========================
 river                50
airplane             50
baseballdiamond      50
agricultural         50
parkinglot           50
freeway              50
sparseresidential    50
mobilehomepark       50
forest               50
intersection         50
runway               50
mediumresidential    50
beach                50
denseresidential     50
buildings            50
tenniscourt          50
chaparral            50
golfcourse           50
storagetanks         50
overpass             50
harbor               50
Name: ClassName, dtype: int64


==========================
VALIDATION
==========================
 mediumresidential    100
runway               100
sparseresidential    100
golfcourse           100
chaparral            100
storagetanks         100
airplane             100
freeway              100
beach                100
forest               100
mobilehomepark       100
buildings            100
overpass             100
river                100
parkinglot           100
harbor               100
intersection         100
baseballdiamond      100
denseresidential     100
tenniscourt          100
agricultural         100
Name: ClassName, dtype: int64
Comentarios:

Como se puede observar, tenemos 21 clases distintas en los 3 ficheros. Nos damos cuenta de que el numero de instancia de los ficheros tiene una buena proporción de los datos, es decir, hay una buena cantidad de datos para hacer el entrenamiento, el test y la posterior validación. Además, observamos que todas las clases tienen datos balanceados.

1.2. Análisis de las carpetas de imágenes.¶

Aunque se supone que cada archivo .csv refleja a la perfección el contenido de cada conjunto de datos, no está demás cerciorarse que el contenido del mismo se corresponde con lo anotado en cada archivo. Para ello se pide:

Ejercicio[0,5 pts]: Proporciona, a partir de las carpetas de imágenes, el número de imágenes que tenemos en cada categoría para cada conjunto de datos, comprobando que coincide con lo estipulado en el archivo .csv, y visualiza a modo de ejemplo una imagen por cada categoría. ¿Qué rango dinámico (valores mínimo y máximo) tienen las imágenes?
In [35]:
# Para el conjunto de datos de entrenamiento
print("\n\n==========================\nTRAIN\n==========================\n")
for conjunto in ['/kaggle/input/landuse-scene-classification/images_train_test_val/train/']:
    for categoria in train['ClassName'].unique():
        carpeta = os.path.join(conjunto, categoria)
        cantidad_imagenes = len(os.listdir(carpeta))
        print("La Categoría:",categoria, "tiene:", cantidad_imagenes, "imágenes")

==========================
TRAIN
==========================

La Categoría: runway tiene: 350 imágenes
La Categoría: intersection tiene: 350 imágenes
La Categoría: agricultural tiene: 350 imágenes
La Categoría: chaparral tiene: 350 imágenes
La Categoría: airplane tiene: 350 imágenes
La Categoría: storagetanks tiene: 350 imágenes
La Categoría: tenniscourt tiene: 350 imágenes
La Categoría: overpass tiene: 350 imágenes
La Categoría: harbor tiene: 350 imágenes
La Categoría: buildings tiene: 350 imágenes
La Categoría: mediumresidential tiene: 350 imágenes
La Categoría: baseballdiamond tiene: 350 imágenes
La Categoría: golfcourse tiene: 350 imágenes
La Categoría: freeway tiene: 350 imágenes
La Categoría: sparseresidential tiene: 350 imágenes
La Categoría: river tiene: 350 imágenes
La Categoría: mobilehomepark tiene: 350 imágenes
La Categoría: forest tiene: 350 imágenes
La Categoría: beach tiene: 350 imágenes
La Categoría: parkinglot tiene: 350 imágenes
La Categoría: denseresidential tiene: 350 imágenes
In [36]:
for categoria in train['ClassName'].unique():
    carpeta = os.path.join('/kaggle/input/landuse-scene-classification/images_train_test_val/train/', categoria)
    archivo_imagen = os.listdir(carpeta)[0]
    ruta_imagen = os.path.join(carpeta, archivo_imagen)
    print(ruta_imagen)
    imagen = cv2.imread(ruta_imagen)
    plt.imshow(imagen)
    plt.title(categoria)
    plt.axis('off')
    plt.show()
/kaggle/input/landuse-scene-classification/images_train_test_val/train/runway/runway_000495.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/intersection/intersection_000175.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/agricultural/agricultural_000139.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/chaparral/chaparral_000278.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/airplane/airplane_000482.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/storagetanks/storagetanks_000207.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/tenniscourt/tenniscourt_000271.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/overpass/overpass_000400.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/harbor/harbor_000183.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/buildings/buildings_000224.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/mediumresidential/mediumresidential_000485.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/baseballdiamond/baseballdiamond_000048.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/golfcourse/golfcourse_000289.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/freeway/freeway_000431.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/sparseresidential/sparseresidential_000222.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/river/river_000378.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/mobilehomepark/mobilehomepark_000126.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/forest/forest_000055.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/beach/beach_000368.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/parkinglot/parkinglot_000156.png
/kaggle/input/landuse-scene-classification/images_train_test_val/train/denseresidential/denseresidential_000001.png
In [37]:
print("\n\n==========================\nTRAIN\n==========================\n")
for categoria in train['ClassName'].unique():
    carpeta = os.path.join('/kaggle/input/landuse-scene-classification/images_train_test_val/train/', categoria)
    archivo_imagen = os.listdir(carpeta)[0]
    ruta_imagen = os.path.join(carpeta, archivo_imagen)
    imagen = cv2.imread(ruta_imagen)
    rango_min = np.min(imagen)
    rango_max = np.max(imagen)
    print("La Categoría:",categoria, "tiene un rango dinámico de entre:", rango_min, "y" ,rango_max)

==========================
TRAIN
==========================

La Categoría: runway tiene un rango dinámico de entre: 1 y 255
La Categoría: intersection tiene un rango dinámico de entre: 0 y 255
La Categoría: agricultural tiene un rango dinámico de entre: 0 y 211
La Categoría: chaparral tiene un rango dinámico de entre: 27 y 255
La Categoría: airplane tiene un rango dinámico de entre: 0 y 206
La Categoría: storagetanks tiene un rango dinámico de entre: 0 y 248
La Categoría: tenniscourt tiene un rango dinámico de entre: 0 y 255
La Categoría: overpass tiene un rango dinámico de entre: 12 y 255
La Categoría: harbor tiene un rango dinámico de entre: 0 y 255
La Categoría: buildings tiene un rango dinámico de entre: 0 y 255
La Categoría: mediumresidential tiene un rango dinámico de entre: 0 y 233
La Categoría: baseballdiamond tiene un rango dinámico de entre: 0 y 250
La Categoría: golfcourse tiene un rango dinámico de entre: 0 y 255
La Categoría: freeway tiene un rango dinámico de entre: 0 y 219
La Categoría: sparseresidential tiene un rango dinámico de entre: 1 y 255
La Categoría: river tiene un rango dinámico de entre: 0 y 247
La Categoría: mobilehomepark tiene un rango dinámico de entre: 29 y 255
La Categoría: forest tiene un rango dinámico de entre: 0 y 255
La Categoría: beach tiene un rango dinámico de entre: 24 y 215
La Categoría: parkinglot tiene un rango dinámico de entre: 0 y 255
La Categoría: denseresidential tiene un rango dinámico de entre: 0 y 255
In [38]:
# Para el conjunto de datos de validación
print("\n\n==========================\nVALIDATION\n==========================\n")
for conjunto in ['/kaggle/input/landuse-scene-classification/images_train_test_val/validation/']:
    for categoria in validation['ClassName'].unique():
        carpeta = os.path.join(conjunto, categoria)
        cantidad_imagenes = len(os.listdir(carpeta))
        print("La Categoría:",categoria, "tiene:", cantidad_imagenes, "imágenes")

==========================
VALIDATION
==========================

La Categoría: mediumresidential tiene: 100 imágenes
La Categoría: buildings tiene: 100 imágenes
La Categoría: tenniscourt tiene: 100 imágenes
La Categoría: denseresidential tiene: 100 imágenes
La Categoría: baseballdiamond tiene: 100 imágenes
La Categoría: intersection tiene: 100 imágenes
La Categoría: harbor tiene: 100 imágenes
La Categoría: parkinglot tiene: 100 imágenes
La Categoría: river tiene: 100 imágenes
La Categoría: overpass tiene: 100 imágenes
La Categoría: mobilehomepark tiene: 100 imágenes
La Categoría: runway tiene: 100 imágenes
La Categoría: forest tiene: 100 imágenes
La Categoría: beach tiene: 100 imágenes
La Categoría: freeway tiene: 100 imágenes
La Categoría: airplane tiene: 100 imágenes
La Categoría: storagetanks tiene: 100 imágenes
La Categoría: chaparral tiene: 100 imágenes
La Categoría: golfcourse tiene: 100 imágenes
La Categoría: sparseresidential tiene: 100 imágenes
La Categoría: agricultural tiene: 100 imágenes
In [39]:
for categoria in validation['ClassName'].unique():
    carpeta = os.path.join('/kaggle/input/landuse-scene-classification/images_train_test_val/validation/', categoria)
    archivo_imagen = os.listdir(carpeta)[0]
    ruta_imagen = os.path.join(carpeta, archivo_imagen)
    print(ruta_imagen)
    imagen = cv2.imread(ruta_imagen)
    plt.imshow(imagen)
    plt.title(categoria)
    plt.axis('off')
    plt.show()
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/mediumresidential/mediumresidential_000148.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/buildings/buildings_000445.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/tenniscourt/tenniscourt_000136.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/denseresidential/denseresidential_000424.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/baseballdiamond/baseballdiamond_000367.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/intersection/intersection_000072.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/harbor/harbor_000187.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/parkinglot/parkinglot_000140.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/river/river_000489.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/overpass/overpass_000150.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/mobilehomepark/mobilehomepark_000066.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/runway/runway_000479.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/forest/forest_000255.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/beach/beach_000362.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/freeway/freeway_000185.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/airplane/airplane_000293.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/storagetanks/storagetanks_000235.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/chaparral/chaparral_000441.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/golfcourse/golfcourse_000300.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/sparseresidential/sparseresidential_000182.png
/kaggle/input/landuse-scene-classification/images_train_test_val/validation/agricultural/agricultural_000037.png
In [40]:
print("\n\n==========================\nVALIDATION\n==========================\n")
for categoria in validation['ClassName'].unique():
    carpeta = os.path.join('/kaggle/input/landuse-scene-classification/images_train_test_val/validation/', categoria)
    archivo_imagen = os.listdir(carpeta)[0]
    ruta_imagen = os.path.join(carpeta, archivo_imagen)
    imagen = cv2.imread(ruta_imagen)
    rango_min = np.min(imagen)
    rango_max = np.max(imagen)
    print("La Categoría:",categoria, "tiene un rango dinámico de entre:", rango_min, "y" ,rango_max)

==========================
VALIDATION
==========================

La Categoría: mediumresidential tiene un rango dinámico de entre: 12 y 255
La Categoría: buildings tiene un rango dinámico de entre: 0 y 203
La Categoría: tenniscourt tiene un rango dinámico de entre: 0 y 255
La Categoría: denseresidential tiene un rango dinámico de entre: 0 y 240
La Categoría: baseballdiamond tiene un rango dinámico de entre: 15 y 255
La Categoría: intersection tiene un rango dinámico de entre: 0 y 255
La Categoría: harbor tiene un rango dinámico de entre: 0 y 255
La Categoría: parkinglot tiene un rango dinámico de entre: 0 y 255
La Categoría: river tiene un rango dinámico de entre: 23 y 255
La Categoría: overpass tiene un rango dinámico de entre: 0 y 206
La Categoría: mobilehomepark tiene un rango dinámico de entre: 0 y 247
La Categoría: runway tiene un rango dinámico de entre: 0 y 255
La Categoría: forest tiene un rango dinámico de entre: 0 y 213
La Categoría: beach tiene un rango dinámico de entre: 18 y 235
La Categoría: freeway tiene un rango dinámico de entre: 14 y 255
La Categoría: airplane tiene un rango dinámico de entre: 12 y 255
La Categoría: storagetanks tiene un rango dinámico de entre: 0 y 255
La Categoría: chaparral tiene un rango dinámico de entre: 0 y 250
La Categoría: golfcourse tiene un rango dinámico de entre: 19 y 255
La Categoría: sparseresidential tiene un rango dinámico de entre: 0 y 220
La Categoría: agricultural tiene un rango dinámico de entre: 0 y 226
In [41]:
# Para el conjunto de datos de test
print("\n\n==========================\nTEST\n==========================\n")
for conjunto in ['/kaggle/input/landuse-scene-classification/images_train_test_val/test/']:
    for categoria in test['ClassName'].unique():
        carpeta = os.path.join(conjunto, categoria)
        cantidad_imagenes = len(os.listdir(carpeta))
        print("La Categoría:",categoria, "tiene:", cantidad_imagenes, "imágenes")

==========================
TEST
==========================

La Categoría: river tiene: 50 imágenes
La Categoría: mediumresidential tiene: 50 imágenes
La Categoría: overpass tiene: 50 imágenes
La Categoría: storagetanks tiene: 50 imágenes
La Categoría: golfcourse tiene: 50 imágenes
La Categoría: chaparral tiene: 50 imágenes
La Categoría: tenniscourt tiene: 50 imágenes
La Categoría: buildings tiene: 50 imágenes
La Categoría: denseresidential tiene: 50 imágenes
La Categoría: beach tiene: 50 imágenes
La Categoría: runway tiene: 50 imágenes
La Categoría: airplane tiene: 50 imágenes
La Categoría: intersection tiene: 50 imágenes
La Categoría: forest tiene: 50 imágenes
La Categoría: mobilehomepark tiene: 50 imágenes
La Categoría: sparseresidential tiene: 50 imágenes
La Categoría: freeway tiene: 50 imágenes
La Categoría: parkinglot tiene: 50 imágenes
La Categoría: agricultural tiene: 50 imágenes
La Categoría: baseballdiamond tiene: 50 imágenes
La Categoría: harbor tiene: 50 imágenes
In [42]:
for categoria in test['ClassName'].unique():
    carpeta = os.path.join('/kaggle/input/landuse-scene-classification/images_train_test_val/test/', categoria)
    archivo_imagen = os.listdir(carpeta)[0]
    ruta_imagen = os.path.join(carpeta, archivo_imagen)
    print(ruta_imagen)
    imagen = cv2.imread(ruta_imagen)
    plt.imshow(imagen)
    plt.title(categoria)
    plt.axis('off')
    plt.show()
/kaggle/input/landuse-scene-classification/images_train_test_val/test/river/river_000133.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/mediumresidential/mediumresidential_000070.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/overpass/overpass_000444.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/storagetanks/storagetanks_000409.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/golfcourse/golfcourse_000120.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/chaparral/chaparral_000280.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/tenniscourt/tenniscourt_000356.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/buildings/buildings_000338.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/denseresidential/denseresidential_000254.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/beach/beach_000357.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/runway/runway_000105.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/airplane/airplane_000058.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/intersection/intersection_000371.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/forest/forest_000247.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/mobilehomepark/mobilehomepark_000317.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/sparseresidential/sparseresidential_000412.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/freeway/freeway_000434.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/parkinglot/parkinglot_000042.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/agricultural/agricultural_000033.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/baseballdiamond/baseballdiamond_000033.png
/kaggle/input/landuse-scene-classification/images_train_test_val/test/harbor/harbor_000418.png
In [43]:
print("\n\n==========================\nTEST\n==========================\n")
for categoria in test['ClassName'].unique():
    carpeta = os.path.join('/kaggle/input/landuse-scene-classification/images_train_test_val/test/', categoria)
    archivo_imagen = os.listdir(carpeta)[0]
    ruta_imagen = os.path.join(carpeta, archivo_imagen)
    imagen = cv2.imread(ruta_imagen)
    rango_min = np.min(imagen)
    rango_max = np.max(imagen)
    print("La Categoría:",categoria, "tiene un rango dinámico de entre:", rango_min, "y" ,rango_max)

==========================
TEST
==========================

La Categoría: river tiene un rango dinámico de entre: 0 y 232
La Categoría: mediumresidential tiene un rango dinámico de entre: 0 y 245
La Categoría: overpass tiene un rango dinámico de entre: 0 y 255
La Categoría: storagetanks tiene un rango dinámico de entre: 0 y 255
La Categoría: golfcourse tiene un rango dinámico de entre: 36 y 255
La Categoría: chaparral tiene un rango dinámico de entre: 0 y 221
La Categoría: tenniscourt tiene un rango dinámico de entre: 0 y 255
La Categoría: buildings tiene un rango dinámico de entre: 0 y 255
La Categoría: denseresidential tiene un rango dinámico de entre: 0 y 244
La Categoría: beach tiene un rango dinámico de entre: 13 y 224
La Categoría: runway tiene un rango dinámico de entre: 24 y 255
La Categoría: airplane tiene un rango dinámico de entre: 0 y 251
La Categoría: intersection tiene un rango dinámico de entre: 0 y 255
La Categoría: forest tiene un rango dinámico de entre: 23 y 188
La Categoría: mobilehomepark tiene un rango dinámico de entre: 0 y 255
La Categoría: sparseresidential tiene un rango dinámico de entre: 0 y 250
La Categoría: freeway tiene un rango dinámico de entre: 0 y 220
La Categoría: parkinglot tiene un rango dinámico de entre: 20 y 234
La Categoría: agricultural tiene un rango dinámico de entre: 0 y 195
La Categoría: baseballdiamond tiene un rango dinámico de entre: 0 y 228
La Categoría: harbor tiene un rango dinámico de entre: 0 y 255

1.3. Creación de los conjuntos de datos en formato Keras/Tensorflow¶

​ Con el objetivo de crear una base de datos en el formato Keras/Tensorflow a partir de las imágenes proporcionadas utilizaremos la función **tf.keras.utils.image_dataset_from_directory()** ya que nos permite crear bases de datos a partir de imágenes guardadas en carpetas.

La documentación de esta función se encuentra tanto en la web de Keras como en la de Tensorflow .

Además, aprovecharemos para redimensionar las imágenes y pasarlas a tamaño 224x224, que es el tamaño con el que se ha entrenado la red VGG16 que utilizaremos en un apartado posterior.

Ejercicio[0,5 pts]: Utiliza la función image_dataset_from_directory() para generar 3 conjuntos de datos (train_data, val_data y test_data) a partir de las carpetas analizadas. Las imágenes deben ser redimensionadas a tamaño 224x224 píxels RGB (224,224,3) y agrupadas en lotes de tamaño 32 (batch=32) manteniendo su rango dinámico.
In [5]:
directorio_entrenamiento = '/kaggle/input/landuse-scene-classification/images_train_test_val/train/'
directorio_validacion = '/kaggle/input/landuse-scene-classification/images_train_test_val/validation/'
directorio_prueba = '/kaggle/input/landuse-scene-classification/images_train_test_val/test/'

train_data = image_dataset_from_directory(
    directorio_entrenamiento,
    image_size=(224, 224),
    batch_size=32,
    shuffle=True,
    seed=42,
    interpolation='bilinear'
)

val_data = image_dataset_from_directory(
    directorio_validacion,
    image_size=(224, 224),
    batch_size=32,
    shuffle=True,
    seed=42,
    interpolation='bilinear'
)

test_data = image_dataset_from_directory(
    directorio_prueba,
    image_size=(224, 224),
    batch_size=32,
    shuffle=True,
    seed=42,
    interpolation='bilinear'
)
Found 7350 files belonging to 21 classes.
Found 2100 files belonging to 21 classes.
Found 1050 files belonging to 21 classes.

2. Modelo ANN (1,5 puntos)¶

En este apartado, vamos a entrenar y evaluar un modelo muy sencillo completamente conectado para establecer un resultado de referencia.

Dado que en una red neuronal artificial las entradas son unidimensionales, lo primero que tenemos que hacer es redimensionar los datos de entrada (las imágenes) para convertirlos en arrays de una dimensión.

Como trabajar con imágenes de tamaño 224x224 en una red completamente conectada implicaría entrenar un número de parámetros excesivamente elevado definiremos un modelo en el que se realizará previamente un redimensionado de las imágenes de entrada a un tamaño de 32x32 y un achatamiento (flattening) de los píxeles para así generar un vector unidimensional de tamaño 3072 (32x32x3).

Posteriormente entrenaremos un clasificador (una red completamente conectada) para llevar a cabo la clasificación de nuestros datos.

En este apartado utilizaremos las capas Resizing, Rescaling, Flatten, Dense y Dropout de keras.

Ejercicio: Implementa un modelo secuencial de Keras (a partir de la clase Sequential()) con las siguientes especificaciones:
  • Una capa que reduzca las dimensiones de entrada de (224,224) a (32,32)
  • Una capa de reescalado para conseguir que los valores de la imagen estén entre 0 y 1
  • Una capa Flatten para convertir la imagen en un vector de 3072 posiciones
  • Una capa completamente conectada de 1024 neuronas y activación ReLU
  • Una capa de Dropout (con probabilidad 0.5)
  • Una capa de salida completamente conectada correspondiente a la clasificación final cuyo número de neuronas debe ser igual al múmero de clases de la base de datos y con la función de activación adecuada para llevar a cabo esta tarea de clasificación.
Compilar y entrenar el modelo siguiendo las siguientes indicaciones:
  • Utilizar el optimizador Adam con learning rate de 0.0001.
  • Entrenar durante 100 épocas utilizando EarlyStopping con una persistencia de 10 épocas, monitorizando la función de pérdida en el conjunto de validación, y guardando los pesos que mejor resultado hayan obtenido.
  • Monitorizar la métrica accuracy durante entrenamiento y validación.
  • Mostrar las gráficas de accuracy y loss. En cada gráfica debe visualizarse la curva de entrenamiento y la de validación. NOTA: Se recomienda hacer una función que imprima ambas gráficas para poder reutilizarla en próximos apartados.
  • Realizar la evaluación del modelo una vez ha finalizado el entrenamiento para mostrar la pérdida y la precisión final sobre los datos de test.
Preguntas a responder: ¿Cúal es el número de parámetros a entrenar? ¿y el tiempo de entrenamiento? ¿Qué precisión se obtiene con este modelo? Comenta los resultados.
NOTA: se recomienda, al final de la creación de cada modelo, utilizar la función summary() para comprobar la estructura de la red creada, así como el numero de parámetros que se deben entrenar. Se recomienda hacerlo en todos los ejercicios.
In [33]:
# Definición de la red
modelo_ANN = Sequential()

# Capa para reducir dimensiones
modelo_ANN.add(Resizing(32, 32, interpolation='bilinear', input_shape=(224, 224, 3)))

# Capa de reescalado
modelo_ANN.add(Rescaling(1./255, offset=0.0))

# Capa de flatten
modelo_ANN.add(Flatten())

# Capa de activacion
modelo_ANN.add(Dense(1024, activation='relu'))

# Capa de dropout
modelo_ANN.add(Dropout(0.5))

# Capa de salida 
modelo_ANN.add(Dense(21, activation='softmax'))
In [34]:
# Compilación de la red
modelo_ANN.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.0001),
              loss=tf.keras.losses.SparseCategoricalCrossentropy(),
              metrics=['accuracy'])
In [35]:
# Definir callbacks
early_stopping = tf.keras.callbacks.EarlyStopping(patience=10, monitor='val_loss', restore_best_weights=True)
checkpoint = tf.keras.callbacks.ModelCheckpoint('mejor_modelo.h5', monitor='val_loss', save_best_only=True)
In [48]:
# Entrenamiento de la red
start_time = time.time()
entrenamiento_ANN = modelo_ANN.fit(train_data, 
                                   epochs=100, 
                                   validation_data=val_data, 
                                   callbacks=[early_stopping, checkpoint])
end_time = time.time()
Epoch 1/100
230/230 [==============================] - 25s 101ms/step - loss: 3.1202 - accuracy: 0.0624 - val_loss: 2.9953 - val_accuracy: 0.1057
Epoch 2/100
230/230 [==============================] - 24s 100ms/step - loss: 3.0013 - accuracy: 0.0898 - val_loss: 2.9710 - val_accuracy: 0.1119
Epoch 3/100
230/230 [==============================] - 23s 99ms/step - loss: 2.9561 - accuracy: 0.1022 - val_loss: 2.9374 - val_accuracy: 0.1171
Epoch 4/100
230/230 [==============================] - 24s 101ms/step - loss: 2.9110 - accuracy: 0.1192 - val_loss: 2.9000 - val_accuracy: 0.1386
Epoch 5/100
230/230 [==============================] - 23s 99ms/step - loss: 2.8658 - accuracy: 0.1377 - val_loss: 2.8695 - val_accuracy: 0.1510
Epoch 6/100
230/230 [==============================] - 24s 101ms/step - loss: 2.8237 - accuracy: 0.1502 - val_loss: 2.8430 - val_accuracy: 0.1567
Epoch 7/100
230/230 [==============================] - 25s 105ms/step - loss: 2.7829 - accuracy: 0.1645 - val_loss: 2.8130 - val_accuracy: 0.1705
Epoch 8/100
230/230 [==============================] - 29s 124ms/step - loss: 2.7458 - accuracy: 0.1727 - val_loss: 2.8011 - val_accuracy: 0.1795
Epoch 9/100
230/230 [==============================] - 24s 102ms/step - loss: 2.7141 - accuracy: 0.1890 - val_loss: 2.7726 - val_accuracy: 0.1957
Epoch 10/100
230/230 [==============================] - 24s 101ms/step - loss: 2.6690 - accuracy: 0.2012 - val_loss: 2.7786 - val_accuracy: 0.1771
Epoch 11/100
230/230 [==============================] - 24s 101ms/step - loss: 2.6411 - accuracy: 0.2082 - val_loss: 2.7521 - val_accuracy: 0.1914
Epoch 12/100
230/230 [==============================] - 23s 98ms/step - loss: 2.6203 - accuracy: 0.2116 - val_loss: 2.7392 - val_accuracy: 0.1929
Epoch 13/100
230/230 [==============================] - 24s 102ms/step - loss: 2.5739 - accuracy: 0.2322 - val_loss: 2.7407 - val_accuracy: 0.1967
Epoch 14/100
230/230 [==============================] - 24s 101ms/step - loss: 2.5538 - accuracy: 0.2392 - val_loss: 2.7008 - val_accuracy: 0.2062
Epoch 15/100
230/230 [==============================] - 29s 123ms/step - loss: 2.5140 - accuracy: 0.2473 - val_loss: 2.6873 - val_accuracy: 0.1957
Epoch 16/100
230/230 [==============================] - 25s 104ms/step - loss: 2.4897 - accuracy: 0.2582 - val_loss: 2.6864 - val_accuracy: 0.2105
Epoch 17/100
230/230 [==============================] - 23s 98ms/step - loss: 2.4524 - accuracy: 0.2754 - val_loss: 2.7011 - val_accuracy: 0.1843
Epoch 18/100
230/230 [==============================] - 24s 103ms/step - loss: 2.4259 - accuracy: 0.2812 - val_loss: 2.6682 - val_accuracy: 0.2124
Epoch 19/100
230/230 [==============================] - 23s 98ms/step - loss: 2.4072 - accuracy: 0.2822 - val_loss: 2.6694 - val_accuracy: 0.2000
Epoch 20/100
230/230 [==============================] - 24s 103ms/step - loss: 2.3627 - accuracy: 0.3019 - val_loss: 2.6445 - val_accuracy: 0.2200
Epoch 21/100
230/230 [==============================] - 24s 103ms/step - loss: 2.3381 - accuracy: 0.3078 - val_loss: 2.6392 - val_accuracy: 0.2181
Epoch 22/100
230/230 [==============================] - 24s 102ms/step - loss: 2.3117 - accuracy: 0.3268 - val_loss: 2.6297 - val_accuracy: 0.2238
Epoch 23/100
230/230 [==============================] - 24s 102ms/step - loss: 2.2863 - accuracy: 0.3263 - val_loss: 2.6328 - val_accuracy: 0.2229
Epoch 24/100
230/230 [==============================] - 23s 99ms/step - loss: 2.2496 - accuracy: 0.3328 - val_loss: 2.6317 - val_accuracy: 0.2195
Epoch 25/100
230/230 [==============================] - 24s 102ms/step - loss: 2.2355 - accuracy: 0.3460 - val_loss: 2.6352 - val_accuracy: 0.2224
Epoch 26/100
230/230 [==============================] - 24s 103ms/step - loss: 2.2089 - accuracy: 0.3577 - val_loss: 2.6083 - val_accuracy: 0.2238
Epoch 27/100
230/230 [==============================] - 29s 123ms/step - loss: 2.1783 - accuracy: 0.3679 - val_loss: 2.6255 - val_accuracy: 0.2219
Epoch 28/100
230/230 [==============================] - 23s 97ms/step - loss: 2.1515 - accuracy: 0.3720 - val_loss: 2.6149 - val_accuracy: 0.2290
Epoch 29/100
230/230 [==============================] - 24s 101ms/step - loss: 2.1268 - accuracy: 0.3710 - val_loss: 2.6101 - val_accuracy: 0.2205
Epoch 30/100
230/230 [==============================] - 24s 102ms/step - loss: 2.0907 - accuracy: 0.3943 - val_loss: 2.6021 - val_accuracy: 0.2343
Epoch 31/100
230/230 [==============================] - 25s 105ms/step - loss: 2.0700 - accuracy: 0.4005 - val_loss: 2.6052 - val_accuracy: 0.2257
Epoch 32/100
230/230 [==============================] - 23s 99ms/step - loss: 2.0369 - accuracy: 0.4103 - val_loss: 2.6077 - val_accuracy: 0.2319
Epoch 33/100
230/230 [==============================] - 24s 100ms/step - loss: 2.0132 - accuracy: 0.4200 - val_loss: 2.5866 - val_accuracy: 0.2410
Epoch 34/100
230/230 [==============================] - 25s 104ms/step - loss: 1.9992 - accuracy: 0.4152 - val_loss: 2.5859 - val_accuracy: 0.2376
Epoch 35/100
230/230 [==============================] - 29s 123ms/step - loss: 1.9624 - accuracy: 0.4348 - val_loss: 2.5994 - val_accuracy: 0.2200
Epoch 36/100
230/230 [==============================] - 24s 101ms/step - loss: 1.9350 - accuracy: 0.4439 - val_loss: 2.6008 - val_accuracy: 0.2286
Epoch 37/100
230/230 [==============================] - 26s 111ms/step - loss: 1.9264 - accuracy: 0.4454 - val_loss: 2.5698 - val_accuracy: 0.2371
Epoch 38/100
230/230 [==============================] - 24s 103ms/step - loss: 1.8909 - accuracy: 0.4475 - val_loss: 2.5929 - val_accuracy: 0.2395
Epoch 39/100
230/230 [==============================] - 26s 112ms/step - loss: 1.8726 - accuracy: 0.4601 - val_loss: 2.5826 - val_accuracy: 0.2343
Epoch 40/100
230/230 [==============================] - 28s 118ms/step - loss: 1.8471 - accuracy: 0.4748 - val_loss: 2.5810 - val_accuracy: 0.2452
Epoch 41/100
230/230 [==============================] - 25s 105ms/step - loss: 1.8096 - accuracy: 0.4796 - val_loss: 2.5968 - val_accuracy: 0.2338
Epoch 42/100
230/230 [==============================] - 32s 137ms/step - loss: 1.7910 - accuracy: 0.4812 - val_loss: 2.5934 - val_accuracy: 0.2486
Epoch 43/100
230/230 [==============================] - 27s 113ms/step - loss: 1.7576 - accuracy: 0.5004 - val_loss: 2.5880 - val_accuracy: 0.2462
Epoch 44/100
230/230 [==============================] - 25s 105ms/step - loss: 1.7329 - accuracy: 0.5102 - val_loss: 2.5824 - val_accuracy: 0.2329
Epoch 45/100
230/230 [==============================] - 24s 104ms/step - loss: 1.7276 - accuracy: 0.4997 - val_loss: 2.5952 - val_accuracy: 0.2510
Epoch 46/100
230/230 [==============================] - 26s 109ms/step - loss: 1.6883 - accuracy: 0.5162 - val_loss: 2.5942 - val_accuracy: 0.2481
Epoch 47/100
230/230 [==============================] - 25s 108ms/step - loss: 1.6700 - accuracy: 0.5147 - val_loss: 2.5956 - val_accuracy: 0.2448
In [11]:
#Función para mostrar las gráficas de Accuracy y Perdida
def mostrar_graficas(modelo):
    acc = modelo.history['accuracy']
    val_acc = modelo.history['val_accuracy']
    loss = modelo.history['loss']
    val_loss = modelo.history['val_loss']
    epochs_range = range(len(acc))

    plt.figure(figsize=(16, 8))
    plt.subplot(1, 2, 1)
    plt.plot(epochs_range, acc, label='Accuracy entrenamiento')
    plt.plot(epochs_range, val_acc, label='Accuracy validación')
    plt.legend(loc='lower right')
    plt.title('Accuracy durante entrenamiento y validación')

    plt.subplot(1, 2, 2)
    plt.plot(epochs_range, loss, label='Pérdida entrenamiento')
    plt.plot(epochs_range, val_loss, label='Pérdida validación')
    plt.legend(loc='upper right')
    plt.title('Pérdida durante entrenamiento y validación')
    plt.show()
In [50]:
# Plot del training loss i l'accuracy
mostrar_graficas(entrenamiento_ANN)
In [36]:
#Información del modelo
modelo_ANN.summary() 
Model: "sequential_3"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 resizing_1 (Resizing)       (None, 32, 32, 3)         0         
                                                                 
 rescaling_2 (Rescaling)     (None, 32, 32, 3)         0         
                                                                 
 flatten_4 (Flatten)         (None, 3072)              0         
                                                                 
 dense_13 (Dense)            (None, 1024)              3146752   
                                                                 
 dropout_2 (Dropout)         (None, 1024)              0         
                                                                 
 dense_14 (Dense)            (None, 21)                21525     
                                                                 
=================================================================
Total params: 3,168,277
Trainable params: 3,168,277
Non-trainable params: 0
_________________________________________________________________
In [52]:
# Estadísticas y resultados del modelo 
test_loss, test_acc = modelo_ANN.evaluate(test_data)

print("\nTiempo de entrenamiento:", end_time - start_time)
print('Pérdida en el conjunto de test:', test_loss)
print('Precisión en el conjunto de test:', test_acc)
33/33 [==============================] - 5s 113ms/step - loss: 2.5913 - accuracy: 0.2429

Tiempo de entrenamiento: 1311.375783920288
Pérdida en el conjunto de test: 2.5913305282592773
Precisión en el conjunto de test: 0.24285714328289032
Comentarios:

Las respuestas a las preguntas planteadas son: * ¿Cúal es el número de parámetros a entrenar? 3,168,277 * ¿Y el tiempo de entrenamiento? El tiempo total de entrenamiento ha sido de aproximadamente de 21 minutos * ¿Qué precisión se obtiene con este modelo? 24,28% Como se puede comprobar la precisión del modelo es bajo teniendo un alto numero de perdidas en el conjunto de test. En las graficas anteriores se puede comprobar de una manera visual lo que los datos numéricos nos dicen.Por lo que podemos concluir que no es un buen modelo.

3. Red convolucional pequeña (2 puntos)¶

Dadas las bajas prestaciones del modelo anterior vamos a probar otro tipo de redes con el objetivo de obtener unos mejores resultados en la tarea de clasificación que debemos llevar a cabo.

Las redes convolucionales (CNN) son especialmente adecuadas para modelar datos donde hay patrones en 2 dimensiones, como es el caso de las imágenes.

En la tarea de clasificación, la estructura de una CNN se divide en dos grandes bloques:

  • Bloque extractor de características: En este bloque se generan diferentes niveles de abstracción de la imagen de entrada mediante capas convolucionales. Cuanto más profundas son estas capas, más preparadas están para la tarea de clasificación.
  • Clasificador: Este bloque está formado por capas totalmente conectadas, la salida de deste bloque será la probabilidad asociada a cada clase.

En el apartado anterior, el bloque "extractor de características" era extremadamente simple, por no decir inexistente. En este apartado, vamos a hacer uso de capas convolucionales para poder aprender mejores abstracciones de las imágenes de entrada con el fin de mejorar su clasificación.

En este apartado utilizaremos las capas Conv2D, MaxPooling2D, GlobalAveragePooling2D, Dense y Dropout de keras.

Nota: Se recomienda, a partir de este punto realizar el entrenamiento en una máquina con GPU (puede activarse en plataformas como Google Colab o Kaggle) con el fin de reducir los tiempos de entrenamiento.

Ejercicio [2 puntos]: A partir del modelo funcional de keras (y la clase Model()), implementa una red con las siguientes características:
  • Un bloque extractor de características que conste de:
    • Una capa de entrada de dimensiones adecuadas a los datos.
    • Una capa de rescalado para conseguir que los valores de la imagen estén entre 0 y 1.
    • 3 capas convolucionales con tamaño de kernel (5x5) para la primera y (3x3) para las 2 siguientes. Se utilizará padding 'same' y activación ReLU. El número de filtros para cada capa convolucional será 16, 32 y 64 respectivamente.
    • A cada capa convolucional le sigue una capa de Max Pooling
    • Una capa de average pooling (GlobalAveragePooling2D) para reducir las dimensiones a un vector de 1024 dimensiones.
  • El clasificador final sigue la estructura del modelo del apartado anterior:
    • Una capa completamente conectada de 1024 neuronas y activación ReLU
    • Una capa de Dropout (con probabilidad 0.5)
    • Una capa de salida completamente conectada correspondiente a la clasificación final cuyo número de neuronas debe ser igual al múmero de clases de la base de datos y con la función de activación adecuada para llevar a cabo esta tarea de clasificación.
Compilar y entrenar el modelo siguiendo las siguientes indicaciones:
  • Utilizar el optimizador Adam con learning rate de 0.001.
  • Entrenar durante 100 épocas utilizando EarlyStopping con una persistencia de 10 épocas, monitorizando la función de pérdida en el conjunto de validación, y guardando los pesos que mejor resultado hayan obtenido.
  • Monitorizar la métrica accuracy durante entrenamiento y validación.
  • Mostrar las gráficas de accuracy y loss. En cada gráfica debe visualizarse la curva de entrenamiento y la de validación.
  • Realizar la evaluación del modelo una vez ha finalizado el entrenamiento para mostrar la pérdida y la precisión final sobre los datos de test.
Preguntas a responder: ¿Cúal es el número de parámetros a entrenar? ¿y el tiempo de entrenamiento? ¿Qué precisión se obtiene con este modelo? Comenta los resultados.
In [37]:
# Definición de la red

# Dimensiones de entrada de los datos
input_shape = (224, 224, 3)

# Capa de entrada
input_layer = Input(shape=input_shape)

# Capa de rescalado
rescale_layer = Rescaling(scale=1./255)(input_layer)

# Bloque extractor de características

## Capa 1
conv1_layer = Conv2D(filters=16, kernel_size=(5, 5), padding='same', activation='relu')(rescale_layer)
pool1_layer = MaxPooling2D(pool_size=(2, 2))(conv1_layer)

## Capa 2
conv2_layer = Conv2D(filters=32, kernel_size=(3, 3), padding='same', activation='relu')(pool1_layer)
pool2_layer = MaxPooling2D(pool_size=(2, 2))(conv2_layer)

## Capa 3
conv3_layer = Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation='relu')(pool2_layer)
pool3_layer = MaxPooling2D(pool_size=(2, 2))(conv3_layer)

## Capa Global
global_pool_layer = GlobalAveragePooling2D()(pool3_layer)

# Clasificador final
dense1_layer = Dense(units=64, activation='relu')(global_pool_layer)
dropout_layer = Dropout(rate=0.5)(dense1_layer)

# Capa Salida
output_layer = Dense(units=21, activation='softmax')(dropout_layer)

# Crear modelo
modelo_CNN = Model(inputs=input_layer, outputs=output_layer)
In [38]:
# Compilación de la red
optimizer = Adam(learning_rate=0.001)
modelo_CNN.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
In [39]:
# EarlyStopping y ModelCheckpoint
earlystop_callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)
checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(filepath='best_weights.h5', monitor='val_loss', save_best_only=True)
In [56]:
# Entrenamiento
start_time = time.time()
entrenamiento_CNN = modelo_CNN.fit(train_data,
                                   epochs=100,
                                   validation_data=val_data,
                                   callbacks=[earlystop_callback, checkpoint_callback])
end_time = time.time()
Epoch 1/100
230/230 [==============================] - 30s 115ms/step - loss: 2.9846 - accuracy: 0.0718 - val_loss: 2.8500 - val_accuracy: 0.1043
Epoch 2/100
230/230 [==============================] - 27s 116ms/step - loss: 2.7975 - accuracy: 0.1139 - val_loss: 2.6644 - val_accuracy: 0.1814
Epoch 3/100
230/230 [==============================] - 27s 115ms/step - loss: 2.6134 - accuracy: 0.1776 - val_loss: 2.4507 - val_accuracy: 0.2386
Epoch 4/100
230/230 [==============================] - 28s 118ms/step - loss: 2.4740 - accuracy: 0.2193 - val_loss: 2.3554 - val_accuracy: 0.2586
Epoch 5/100
230/230 [==============================] - 25s 104ms/step - loss: 2.3524 - accuracy: 0.2527 - val_loss: 2.1594 - val_accuracy: 0.3571
Epoch 6/100
230/230 [==============================] - 25s 107ms/step - loss: 2.2815 - accuracy: 0.2834 - val_loss: 2.0599 - val_accuracy: 0.3629
Epoch 7/100
230/230 [==============================] - 26s 109ms/step - loss: 2.1528 - accuracy: 0.3159 - val_loss: 1.9498 - val_accuracy: 0.4043
Epoch 8/100
230/230 [==============================] - 25s 106ms/step - loss: 2.0830 - accuracy: 0.3328 - val_loss: 1.9358 - val_accuracy: 0.3914
Epoch 9/100
230/230 [==============================] - 24s 103ms/step - loss: 2.0370 - accuracy: 0.3509 - val_loss: 1.8618 - val_accuracy: 0.3986
Epoch 10/100
230/230 [==============================] - 25s 107ms/step - loss: 1.9953 - accuracy: 0.3525 - val_loss: 1.8303 - val_accuracy: 0.4081
Epoch 11/100
230/230 [==============================] - 25s 108ms/step - loss: 1.9467 - accuracy: 0.3722 - val_loss: 1.7878 - val_accuracy: 0.4381
Epoch 12/100
230/230 [==============================] - 25s 104ms/step - loss: 1.9048 - accuracy: 0.3808 - val_loss: 1.7146 - val_accuracy: 0.4543
Epoch 13/100
230/230 [==============================] - 25s 107ms/step - loss: 1.8654 - accuracy: 0.3913 - val_loss: 1.6537 - val_accuracy: 0.4795
Epoch 14/100
230/230 [==============================] - 25s 108ms/step - loss: 1.8262 - accuracy: 0.3989 - val_loss: 1.6266 - val_accuracy: 0.4757
Epoch 15/100
230/230 [==============================] - 25s 107ms/step - loss: 1.7999 - accuracy: 0.4113 - val_loss: 1.5969 - val_accuracy: 0.4881
Epoch 16/100
230/230 [==============================] - 26s 110ms/step - loss: 1.7637 - accuracy: 0.4210 - val_loss: 1.5722 - val_accuracy: 0.4862
Epoch 17/100
230/230 [==============================] - 25s 107ms/step - loss: 1.7487 - accuracy: 0.4186 - val_loss: 1.7481 - val_accuracy: 0.4195
Epoch 18/100
230/230 [==============================] - 26s 109ms/step - loss: 1.7385 - accuracy: 0.4291 - val_loss: 1.5673 - val_accuracy: 0.4919
Epoch 19/100
230/230 [==============================] - 26s 109ms/step - loss: 1.7088 - accuracy: 0.4341 - val_loss: 1.4899 - val_accuracy: 0.5195
Epoch 20/100
230/230 [==============================] - 25s 107ms/step - loss: 1.6643 - accuracy: 0.4473 - val_loss: 1.4702 - val_accuracy: 0.5386
Epoch 21/100
230/230 [==============================] - 25s 107ms/step - loss: 1.6488 - accuracy: 0.4512 - val_loss: 1.5057 - val_accuracy: 0.5167
Epoch 22/100
230/230 [==============================] - 25s 105ms/step - loss: 1.6212 - accuracy: 0.4571 - val_loss: 1.4281 - val_accuracy: 0.5490
Epoch 23/100
230/230 [==============================] - 25s 108ms/step - loss: 1.6120 - accuracy: 0.4641 - val_loss: 1.4075 - val_accuracy: 0.5471
Epoch 24/100
230/230 [==============================] - 25s 105ms/step - loss: 1.5665 - accuracy: 0.4767 - val_loss: 1.3818 - val_accuracy: 0.5495
Epoch 25/100
230/230 [==============================] - 25s 104ms/step - loss: 1.5695 - accuracy: 0.4710 - val_loss: 1.3602 - val_accuracy: 0.5681
Epoch 26/100
230/230 [==============================] - 26s 110ms/step - loss: 1.5601 - accuracy: 0.4777 - val_loss: 1.4266 - val_accuracy: 0.5324
Epoch 27/100
230/230 [==============================] - 25s 107ms/step - loss: 1.5519 - accuracy: 0.4714 - val_loss: 1.2849 - val_accuracy: 0.5952
Epoch 28/100
230/230 [==============================] - 25s 106ms/step - loss: 1.5077 - accuracy: 0.4932 - val_loss: 1.3118 - val_accuracy: 0.5762
Epoch 29/100
230/230 [==============================] - 25s 107ms/step - loss: 1.4835 - accuracy: 0.5094 - val_loss: 1.2831 - val_accuracy: 0.5833
Epoch 30/100
230/230 [==============================] - 25s 108ms/step - loss: 1.4896 - accuracy: 0.4980 - val_loss: 1.2901 - val_accuracy: 0.5824
Epoch 31/100
230/230 [==============================] - 25s 106ms/step - loss: 1.4477 - accuracy: 0.5156 - val_loss: 1.2256 - val_accuracy: 0.6024
Epoch 32/100
230/230 [==============================] - 25s 104ms/step - loss: 1.4491 - accuracy: 0.5106 - val_loss: 1.2897 - val_accuracy: 0.5948
Epoch 33/100
230/230 [==============================] - 25s 106ms/step - loss: 1.4445 - accuracy: 0.5186 - val_loss: 1.2264 - val_accuracy: 0.6038
Epoch 34/100
230/230 [==============================] - 25s 106ms/step - loss: 1.4016 - accuracy: 0.5290 - val_loss: 1.1746 - val_accuracy: 0.6190
Epoch 35/100
230/230 [==============================] - 26s 108ms/step - loss: 1.3748 - accuracy: 0.5358 - val_loss: 1.1604 - val_accuracy: 0.6281
Epoch 36/100
230/230 [==============================] - 27s 116ms/step - loss: 1.3562 - accuracy: 0.5373 - val_loss: 1.1750 - val_accuracy: 0.6152
Epoch 37/100
230/230 [==============================] - 26s 110ms/step - loss: 1.3367 - accuracy: 0.5442 - val_loss: 1.1580 - val_accuracy: 0.6262
Epoch 38/100
230/230 [==============================] - 26s 109ms/step - loss: 1.3171 - accuracy: 0.5555 - val_loss: 1.1301 - val_accuracy: 0.6429
Epoch 39/100
230/230 [==============================] - 28s 116ms/step - loss: 1.2987 - accuracy: 0.5551 - val_loss: 1.0858 - val_accuracy: 0.6562
Epoch 40/100
230/230 [==============================] - 25s 105ms/step - loss: 1.3048 - accuracy: 0.5626 - val_loss: 1.0864 - val_accuracy: 0.6543
Epoch 41/100
230/230 [==============================] - 27s 117ms/step - loss: 1.2856 - accuracy: 0.5675 - val_loss: 1.1506 - val_accuracy: 0.6190
Epoch 42/100
230/230 [==============================] - 28s 117ms/step - loss: 1.2627 - accuracy: 0.5728 - val_loss: 1.0392 - val_accuracy: 0.6767
Epoch 43/100
230/230 [==============================] - 28s 120ms/step - loss: 1.2673 - accuracy: 0.5703 - val_loss: 1.0399 - val_accuracy: 0.6633
Epoch 44/100
230/230 [==============================] - 32s 135ms/step - loss: 1.2424 - accuracy: 0.5721 - val_loss: 1.0341 - val_accuracy: 0.6786
Epoch 45/100
230/230 [==============================] - 28s 120ms/step - loss: 1.2378 - accuracy: 0.5777 - val_loss: 1.0298 - val_accuracy: 0.6662
Epoch 46/100
230/230 [==============================] - 27s 114ms/step - loss: 1.2308 - accuracy: 0.5835 - val_loss: 1.0570 - val_accuracy: 0.6633
Epoch 47/100
230/230 [==============================] - 27s 115ms/step - loss: 1.2111 - accuracy: 0.5902 - val_loss: 1.0891 - val_accuracy: 0.6624
Epoch 48/100
230/230 [==============================] - 27s 116ms/step - loss: 1.1983 - accuracy: 0.5864 - val_loss: 1.0575 - val_accuracy: 0.6629
Epoch 49/100
230/230 [==============================] - 28s 115ms/step - loss: 1.1932 - accuracy: 0.5940 - val_loss: 0.9922 - val_accuracy: 0.6867
Epoch 50/100
230/230 [==============================] - 28s 119ms/step - loss: 1.1751 - accuracy: 0.6020 - val_loss: 0.9936 - val_accuracy: 0.6824
Epoch 51/100
230/230 [==============================] - 28s 120ms/step - loss: 1.1546 - accuracy: 0.6007 - val_loss: 0.9989 - val_accuracy: 0.6762
Epoch 52/100
230/230 [==============================] - 29s 122ms/step - loss: 1.1762 - accuracy: 0.6030 - val_loss: 1.0207 - val_accuracy: 0.6862
Epoch 53/100
230/230 [==============================] - 28s 120ms/step - loss: 1.1575 - accuracy: 0.5999 - val_loss: 0.9606 - val_accuracy: 0.6881
Epoch 54/100
230/230 [==============================] - 28s 119ms/step - loss: 1.1274 - accuracy: 0.6139 - val_loss: 0.9547 - val_accuracy: 0.6876
Epoch 55/100
230/230 [==============================] - 29s 122ms/step - loss: 1.1521 - accuracy: 0.5990 - val_loss: 0.9357 - val_accuracy: 0.7090
Epoch 56/100
230/230 [==============================] - 25s 108ms/step - loss: 1.1189 - accuracy: 0.6204 - val_loss: 0.9849 - val_accuracy: 0.6890
Epoch 57/100
230/230 [==============================] - 25s 106ms/step - loss: 1.1059 - accuracy: 0.6150 - val_loss: 0.9126 - val_accuracy: 0.7100
Epoch 58/100
230/230 [==============================] - 26s 109ms/step - loss: 1.0754 - accuracy: 0.6246 - val_loss: 0.8979 - val_accuracy: 0.7124
Epoch 59/100
230/230 [==============================] - 25s 107ms/step - loss: 1.0847 - accuracy: 0.6272 - val_loss: 0.9432 - val_accuracy: 0.7005
Epoch 60/100
230/230 [==============================] - 25s 107ms/step - loss: 1.0891 - accuracy: 0.6286 - val_loss: 1.0063 - val_accuracy: 0.6776
Epoch 61/100
230/230 [==============================] - 25s 106ms/step - loss: 1.0715 - accuracy: 0.6284 - val_loss: 0.9179 - val_accuracy: 0.7062
Epoch 62/100
230/230 [==============================] - 25s 107ms/step - loss: 1.0856 - accuracy: 0.6273 - val_loss: 0.9611 - val_accuracy: 0.6976
Epoch 63/100
230/230 [==============================] - 31s 131ms/step - loss: 1.0537 - accuracy: 0.6377 - val_loss: 0.9231 - val_accuracy: 0.7200
Epoch 64/100
230/230 [==============================] - 30s 128ms/step - loss: 1.0502 - accuracy: 0.6321 - val_loss: 0.9461 - val_accuracy: 0.7095
Epoch 65/100
230/230 [==============================] - 24s 104ms/step - loss: 1.0596 - accuracy: 0.6388 - val_loss: 0.9513 - val_accuracy: 0.7067
Epoch 66/100
230/230 [==============================] - 26s 109ms/step - loss: 1.0459 - accuracy: 0.6448 - val_loss: 0.9216 - val_accuracy: 0.7148
Epoch 67/100
230/230 [==============================] - 26s 111ms/step - loss: 1.0218 - accuracy: 0.6464 - val_loss: 0.8613 - val_accuracy: 0.7371
Epoch 68/100
230/230 [==============================] - 25s 107ms/step - loss: 1.0203 - accuracy: 0.6469 - val_loss: 0.8488 - val_accuracy: 0.7295
Epoch 69/100
230/230 [==============================] - 25s 108ms/step - loss: 1.0048 - accuracy: 0.6522 - val_loss: 0.8697 - val_accuracy: 0.7338
Epoch 70/100
230/230 [==============================] - 25s 106ms/step - loss: 1.0246 - accuracy: 0.6484 - val_loss: 0.8886 - val_accuracy: 0.7210
Epoch 71/100
230/230 [==============================] - 25s 107ms/step - loss: 0.9903 - accuracy: 0.6595 - val_loss: 0.8418 - val_accuracy: 0.7414
Epoch 72/100
230/230 [==============================] - 26s 113ms/step - loss: 0.9887 - accuracy: 0.6645 - val_loss: 0.8353 - val_accuracy: 0.7381
Epoch 73/100
230/230 [==============================] - 28s 117ms/step - loss: 1.0041 - accuracy: 0.6536 - val_loss: 0.8782 - val_accuracy: 0.7229
Epoch 74/100
230/230 [==============================] - 25s 108ms/step - loss: 0.9749 - accuracy: 0.6652 - val_loss: 0.8395 - val_accuracy: 0.7376
Epoch 75/100
230/230 [==============================] - 27s 116ms/step - loss: 0.9618 - accuracy: 0.6686 - val_loss: 0.8133 - val_accuracy: 0.7481
Epoch 76/100
230/230 [==============================] - 25s 108ms/step - loss: 0.9828 - accuracy: 0.6569 - val_loss: 0.8271 - val_accuracy: 0.7452
Epoch 77/100
230/230 [==============================] - 25s 108ms/step - loss: 0.9718 - accuracy: 0.6683 - val_loss: 0.8498 - val_accuracy: 0.7452
Epoch 78/100
230/230 [==============================] - 25s 107ms/step - loss: 0.9499 - accuracy: 0.6702 - val_loss: 0.8228 - val_accuracy: 0.7376
Epoch 79/100
230/230 [==============================] - 25s 108ms/step - loss: 0.9585 - accuracy: 0.6713 - val_loss: 0.8034 - val_accuracy: 0.7533
Epoch 80/100
230/230 [==============================] - 25s 107ms/step - loss: 0.9492 - accuracy: 0.6724 - val_loss: 0.8763 - val_accuracy: 0.7395
Epoch 81/100
230/230 [==============================] - 30s 129ms/step - loss: 0.9240 - accuracy: 0.6805 - val_loss: 0.7861 - val_accuracy: 0.7686
Epoch 82/100
230/230 [==============================] - 26s 111ms/step - loss: 0.9387 - accuracy: 0.6735 - val_loss: 0.8965 - val_accuracy: 0.7205
Epoch 83/100
230/230 [==============================] - 26s 110ms/step - loss: 0.9320 - accuracy: 0.6810 - val_loss: 0.7969 - val_accuracy: 0.7524
Epoch 84/100
230/230 [==============================] - 24s 104ms/step - loss: 0.9111 - accuracy: 0.6884 - val_loss: 0.8365 - val_accuracy: 0.7490
Epoch 85/100
230/230 [==============================] - 25s 106ms/step - loss: 0.9044 - accuracy: 0.6819 - val_loss: 0.8095 - val_accuracy: 0.7567
Epoch 86/100
230/230 [==============================] - 31s 130ms/step - loss: 0.8838 - accuracy: 0.6899 - val_loss: 0.8298 - val_accuracy: 0.7471
Epoch 87/100
230/230 [==============================] - 25s 107ms/step - loss: 0.9066 - accuracy: 0.6879 - val_loss: 0.7851 - val_accuracy: 0.7586
Epoch 88/100
230/230 [==============================] - 26s 109ms/step - loss: 0.8870 - accuracy: 0.6947 - val_loss: 0.8091 - val_accuracy: 0.7533
Epoch 89/100
230/230 [==============================] - 25s 107ms/step - loss: 0.9094 - accuracy: 0.6891 - val_loss: 0.7693 - val_accuracy: 0.7614
Epoch 90/100
230/230 [==============================] - 26s 109ms/step - loss: 0.8691 - accuracy: 0.6993 - val_loss: 0.7620 - val_accuracy: 0.7676
Epoch 91/100
230/230 [==============================] - 25s 107ms/step - loss: 0.8818 - accuracy: 0.6895 - val_loss: 0.7321 - val_accuracy: 0.7790
Epoch 92/100
230/230 [==============================] - 25s 106ms/step - loss: 0.8804 - accuracy: 0.6971 - val_loss: 0.7854 - val_accuracy: 0.7538
Epoch 93/100
230/230 [==============================] - 25s 107ms/step - loss: 0.8760 - accuracy: 0.6914 - val_loss: 0.7808 - val_accuracy: 0.7652
Epoch 94/100
230/230 [==============================] - 26s 109ms/step - loss: 0.8773 - accuracy: 0.6978 - val_loss: 0.7723 - val_accuracy: 0.7681
Epoch 95/100
230/230 [==============================] - 30s 127ms/step - loss: 0.8439 - accuracy: 0.7071 - val_loss: 0.7191 - val_accuracy: 0.7805
Epoch 96/100
230/230 [==============================] - 25s 105ms/step - loss: 0.8549 - accuracy: 0.7001 - val_loss: 0.7836 - val_accuracy: 0.7590
Epoch 97/100
230/230 [==============================] - 25s 106ms/step - loss: 0.8462 - accuracy: 0.7068 - val_loss: 0.7303 - val_accuracy: 0.7700
Epoch 98/100
230/230 [==============================] - 26s 108ms/step - loss: 0.8311 - accuracy: 0.7078 - val_loss: 0.7301 - val_accuracy: 0.7752
Epoch 99/100
230/230 [==============================] - 26s 111ms/step - loss: 0.8355 - accuracy: 0.7170 - val_loss: 0.6911 - val_accuracy: 0.7862
Epoch 100/100
230/230 [==============================] - 28s 117ms/step - loss: 0.8611 - accuracy: 0.7065 - val_loss: 0.7383 - val_accuracy: 0.7662
In [57]:
# Plot del training loss i l'accuracy
mostrar_graficas(entrenamiento_CNN)
In [40]:
#Información del modelo
modelo_CNN.summary() 
Model: "model_2"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_5 (InputLayer)        [(None, 224, 224, 3)]     0         
                                                                 
 rescaling_3 (Rescaling)     (None, 224, 224, 3)       0         
                                                                 
 conv2d_6 (Conv2D)           (None, 224, 224, 16)      1216      
                                                                 
 max_pooling2d_3 (MaxPooling  (None, 112, 112, 16)     0         
 2D)                                                             
                                                                 
 conv2d_7 (Conv2D)           (None, 112, 112, 32)      4640      
                                                                 
 max_pooling2d_4 (MaxPooling  (None, 56, 56, 32)       0         
 2D)                                                             
                                                                 
 conv2d_8 (Conv2D)           (None, 56, 56, 64)        18496     
                                                                 
 max_pooling2d_5 (MaxPooling  (None, 28, 28, 64)       0         
 2D)                                                             
                                                                 
 global_average_pooling2d_1   (None, 64)               0         
 (GlobalAveragePooling2D)                                        
                                                                 
 dense_15 (Dense)            (None, 64)                4160      
                                                                 
 dropout_3 (Dropout)         (None, 64)                0         
                                                                 
 dense_16 (Dense)            (None, 21)                1365      
                                                                 
=================================================================
Total params: 29,877
Trainable params: 29,877
Non-trainable params: 0
_________________________________________________________________
In [59]:
# Estadísticas y resultados del modelo 
test_loss, test_acc = modelo_CNN.evaluate(test_data)

print("\nTiempo de entrenamiento:", end_time - start_time)
print('Pérdida en el conjunto de test:', test_loss)
print('Precisión en el conjunto de test:', test_acc)
33/33 [==============================] - 3s 66ms/step - loss: 0.7314 - accuracy: 0.7562

Tiempo de entrenamiento: 2858.381495952606
Pérdida en el conjunto de test: 0.7313904762268066
Precisión en el conjunto de test: 0.7561904788017273
Comentarios:

Las respuestas a las preguntas planteadas son: * ¿Cúal es el número de parámetros a entrenar? 29,877 * ¿Y el tiempo de entrenamiento? El tiempo total de entrenamiento ha sido aproximadamente de 47 minutos * ¿Qué precisión se obtiene con este modelo? 75,6% Como se puede comprobar la precisión del modelo mucho mayor que el modelo anterior, esto se debe a todas las mejoras de este modelo (esta precisión se puede ver también de una manera visual y numérica). Por otro lado el número de parámetros ha sido menor que en el modelo anterior.

4. Autoencoders (2 puntos)¶

En el apartado anterior hemos podido observar que, utilizando el tipo de redes adecuado, podemos obtener mejores resultados entrenando un número de parámetros muy inferior. Esto es debido a que las CNN consiguen extraer las características principales de los datos proporcionados (imágenes en nuestro caso).

En este apartado vamos a observar esta capacidad desde otro punto de vista: el de codificar y decodificar una imagen.

Para ello diseñaremos un autoencoder que sea capaz de reducir el tamaño de los datos de entrada pero captando las características principales de las imágenes para poder llevar a cabo una buena reconstrucción de las mismas.

Empezaremos rescalando externamente los datos que vamos a utilizar, para que estén en el rango (0,1), en lugar de realizarlo dentro de la red como hemos hecho en el apartado anterior:

In [60]:
# data rescalling
normalization_layer = Rescaling(1./255)

normalized_train_data = train_data.map(lambda x, y: (normalization_layer(x), y))
normalized_val_data = val_data.map(lambda x, y: (normalization_layer(x), y))

Además, en un autoencoder, en lugar de utilizar las etiquetas como objetivo (que es lo que se utiliza en un problema de clasificación), deben ser las propias imágenes las que se utilicen como objetivo de la red. Por tanto, crearemos una nueva base de datos de entrenamiento y validación donde son las propias imágenes las que hagan de etiquetas:

In [61]:
train_data_auto = normalized_train_data.map(lambda x, y: (x, x))
val_data_auto = normalized_val_data.map(lambda x, y: (x, x))

Comprobamos la estructura de la nueva base de datos:

In [62]:
image_batch, label_batch = iter(train_data_auto).get_next()
print("Las dimensiones de un batch de imágenes es: {}".format(image_batch.shape))
print("Las dimensiones de un batch de etiquetas es: {}".format(label_batch.shape))
Las dimensiones de un batch de imágenes es: (32, 224, 224, 3)
Las dimensiones de un batch de etiquetas es: (32, 224, 224, 3)

Y que los datos tienen el rango dinámico adecuado:

In [63]:
first_image = image_batch[0]
print("En la primera imagen los valores mínimo y máximo son {} y {}, respectivamente"
      .format(np.min(first_image),np.max(first_image)))
En la primera imagen los valores mínimo y máximo son 0.04708659648895264 y 0.9444637298583984, respectivamente

4.1. Diseño y entrenamiento del autoencoder¶

Una vez ya tenemos los datos en el formato adecuado vamos a diseñar el autoencoder. Para ello utilizaremos el bloque extractor del apartado anterior como codificador y reflejaremos su estructura en el decodificador utilizando las capas Conv2DTranspose y UpSampling2D de keras.

Ejercicio [1 punto]: A partir del modelo funcional de keras (y la clase Model()), implementa un autoencoder con las siguientes características:
  • El bloque codificador debe tener:
    • Una capa de entrada de dimensiones adecuadas a los datos.
    • 3 capas convolucionales con tamaño de kernel (5x5) para la primera y (3x3) para las 2 siguientes. Se utilizará padding 'same' y activación ReLU. El número de filtros para cada capa convolucional será 16, 32 y 64 respectivamente.
    • A cada capa convolucional le sigue una capa de Max Pooling
  • El bloque decodificador debe tener:
    • 3 capas convolucionales con tamaño de kernel (3x3) para las 2 primeras y (5x5) para la última. Se utilizará padding 'same' y activación ReLU. El número de filtros para cada capa convolucional será 64, 32 y 16, respectivamente
    • A cada capa convolucional le sigue una capa de UpSampling2D
    • Una última capa convolucional con tamaño de kernel (3x3), con 3 filtros y activación sigmoide.
Compilar y entrenar el modelo siguiendo las siguientes indicaciones:
  • Utilizar el optimizador Adam con learning rate de 0.001.
  • Utilizar como función de pérdida el error cuadrático medio.
  • Entrenar durante 100 épocas utilizando EarlyStopping con una persistencia de 10 épocas, monitorizando la función de pérdida en el conjunto de validación, y guardando los pesos que mejor resultado hayan obtenido.
  • Monitorizar la pérdida durante entrenamiento y validación.
  • Mostrar las gráficas del loss (la curva de entrenamiento y la de validación).
In [41]:
# Definición de la red

# Entrada
input_image = layers.Input(shape=(224, 224, 3))

# Capas convolucionales del codificador
## Capa 1
conv_1 = Conv2D(16, (5, 5), padding='same', activation='relu')(input_image)
pool_1 = MaxPooling2D((2, 2), padding='same')(conv_1)
## Capa 2
conv_2 = Conv2D(32, (3, 3), padding='same', activation='relu')(pool_1)
pool_2 = MaxPooling2D((2, 2), padding='same')(conv_2)
## Capa 3
conv_3 = Conv2D(64, (3, 3), padding='same', activation='relu')(pool_2)
encoder_output = MaxPooling2D((2, 2), padding='same')(conv_3)

# Capas convolucionales del decodificador
## Capa 1
deconv_1 = Conv2DTranspose(64, (3, 3), padding='same', activation='relu')(encoder_output)
upsample_1 = UpSampling2D((2, 2))(deconv_1)
## Capa 2
deconv_2 = Conv2DTranspose(32, (3, 3), padding='same', activation='relu')(upsample_1)
upsample_2 = UpSampling2D((2, 2))(deconv_2)
## Capa 3
deconv_3 = Conv2DTranspose(16, (5, 5), padding='same', activation='relu')(upsample_2)
upsample_3 = UpSampling2D((2, 2))(deconv_3)

decoder_output = Conv2DTranspose(3, (3, 3), padding='same', activation='sigmoid')(upsample_3)

# Definir modelo completo
modelo_autoencoder = Model(input_image, decoder_output)
In [65]:
# Compilación de la red
optimizer = Adam(learning_rate=0.001)
modelo_autoencoder.compile(optimizer=optimizer, metrics=['accuracy'], loss='mean_squared_error')
In [66]:
# Definir EarlyStopping y ModelCheckpoint
early_stopping =  tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=10, mode='min')
checkpoint = tf.keras.callbacks.ModelCheckpoint('best_model.h5', monitor='val_loss', save_best_only=True, mode='min')
In [67]:
# Entrenamiento de la red
start_time = time.time()
entrenamiento_autoencoder = modelo_autoencoder.fit(train_data_auto, 
                                          epochs=100, 
                                          validation_data=val_data_auto,
                                          callbacks=[early_stopping, checkpoint])
end_time = time.time()
Epoch 1/100
230/230 [==============================] - 31s 127ms/step - loss: 0.0151 - accuracy: 0.4605 - val_loss: 0.0067 - val_accuracy: 0.5416
Epoch 2/100
230/230 [==============================] - 31s 132ms/step - loss: 0.0061 - accuracy: 0.5985 - val_loss: 0.0051 - val_accuracy: 0.6712
Epoch 3/100
230/230 [==============================] - 35s 149ms/step - loss: 0.0049 - accuracy: 0.6816 - val_loss: 0.0048 - val_accuracy: 0.6914
Epoch 4/100
230/230 [==============================] - 30s 127ms/step - loss: 0.0044 - accuracy: 0.6949 - val_loss: 0.0040 - val_accuracy: 0.6817
Epoch 5/100
230/230 [==============================] - 30s 126ms/step - loss: 0.0040 - accuracy: 0.7024 - val_loss: 0.0039 - val_accuracy: 0.7079
Epoch 6/100
230/230 [==============================] - 28s 119ms/step - loss: 0.0038 - accuracy: 0.7041 - val_loss: 0.0035 - val_accuracy: 0.7005
Epoch 7/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0037 - accuracy: 0.7035 - val_loss: 0.0033 - val_accuracy: 0.7105
Epoch 8/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0035 - accuracy: 0.7031 - val_loss: 0.0033 - val_accuracy: 0.6476
Epoch 9/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0033 - accuracy: 0.7053 - val_loss: 0.0031 - val_accuracy: 0.7140
Epoch 10/100
230/230 [==============================] - 33s 141ms/step - loss: 0.0033 - accuracy: 0.7002 - val_loss: 0.0032 - val_accuracy: 0.7096
Epoch 11/100
230/230 [==============================] - 29s 124ms/step - loss: 0.0031 - accuracy: 0.7056 - val_loss: 0.0029 - val_accuracy: 0.6986
Epoch 12/100
230/230 [==============================] - 31s 131ms/step - loss: 0.0030 - accuracy: 0.7055 - val_loss: 0.0028 - val_accuracy: 0.7129
Epoch 13/100
230/230 [==============================] - 30s 128ms/step - loss: 0.0029 - accuracy: 0.7095 - val_loss: 0.0031 - val_accuracy: 0.6980
Epoch 14/100
230/230 [==============================] - 35s 148ms/step - loss: 0.0029 - accuracy: 0.7063 - val_loss: 0.0026 - val_accuracy: 0.7032
Epoch 15/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0028 - accuracy: 0.7063 - val_loss: 0.0027 - val_accuracy: 0.7207
Epoch 16/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0028 - accuracy: 0.7055 - val_loss: 0.0025 - val_accuracy: 0.7172
Epoch 17/100
230/230 [==============================] - 33s 141ms/step - loss: 0.0027 - accuracy: 0.7145 - val_loss: 0.0025 - val_accuracy: 0.7204
Epoch 18/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0027 - accuracy: 0.7097 - val_loss: 0.0025 - val_accuracy: 0.7206
Epoch 19/100
230/230 [==============================] - 33s 141ms/step - loss: 0.0026 - accuracy: 0.7143 - val_loss: 0.0024 - val_accuracy: 0.7059
Epoch 20/100
230/230 [==============================] - 34s 145ms/step - loss: 0.0025 - accuracy: 0.7114 - val_loss: 0.0023 - val_accuracy: 0.7128
Epoch 21/100
230/230 [==============================] - 30s 127ms/step - loss: 0.0025 - accuracy: 0.7128 - val_loss: 0.0023 - val_accuracy: 0.7238
Epoch 22/100
230/230 [==============================] - 30s 127ms/step - loss: 0.0025 - accuracy: 0.7148 - val_loss: 0.0023 - val_accuracy: 0.7178
Epoch 23/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0024 - accuracy: 0.7120 - val_loss: 0.0023 - val_accuracy: 0.7257
Epoch 24/100
230/230 [==============================] - 29s 124ms/step - loss: 0.0024 - accuracy: 0.7171 - val_loss: 0.0022 - val_accuracy: 0.7319
Epoch 25/100
230/230 [==============================] - 33s 139ms/step - loss: 0.0023 - accuracy: 0.7187 - val_loss: 0.0022 - val_accuracy: 0.7286
Epoch 26/100
230/230 [==============================] - 29s 125ms/step - loss: 0.0023 - accuracy: 0.7236 - val_loss: 0.0021 - val_accuracy: 0.7286
Epoch 27/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0025 - accuracy: 0.7057 - val_loss: 0.0021 - val_accuracy: 0.7228
Epoch 28/100
230/230 [==============================] - 28s 119ms/step - loss: 0.0022 - accuracy: 0.7152 - val_loss: 0.0021 - val_accuracy: 0.7260
Epoch 29/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0022 - accuracy: 0.7166 - val_loss: 0.0021 - val_accuracy: 0.7058
Epoch 30/100
230/230 [==============================] - 29s 124ms/step - loss: 0.0022 - accuracy: 0.7225 - val_loss: 0.0020 - val_accuracy: 0.7234
Epoch 31/100
230/230 [==============================] - 28s 120ms/step - loss: 0.0022 - accuracy: 0.7195 - val_loss: 0.0020 - val_accuracy: 0.7404
Epoch 32/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0021 - accuracy: 0.7190 - val_loss: 0.0020 - val_accuracy: 0.7128
Epoch 33/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0021 - accuracy: 0.7208 - val_loss: 0.0020 - val_accuracy: 0.7366
Epoch 34/100
230/230 [==============================] - 29s 125ms/step - loss: 0.0021 - accuracy: 0.7156 - val_loss: 0.0020 - val_accuracy: 0.7190
Epoch 35/100
230/230 [==============================] - 33s 140ms/step - loss: 0.0021 - accuracy: 0.7205 - val_loss: 0.0020 - val_accuracy: 0.7192
Epoch 36/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0020 - accuracy: 0.7258 - val_loss: 0.0019 - val_accuracy: 0.7390
Epoch 37/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0020 - accuracy: 0.7202 - val_loss: 0.0021 - val_accuracy: 0.6858
Epoch 38/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0020 - accuracy: 0.7247 - val_loss: 0.0019 - val_accuracy: 0.7325
Epoch 39/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0020 - accuracy: 0.7180 - val_loss: 0.0020 - val_accuracy: 0.7265
Epoch 40/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0020 - accuracy: 0.7226 - val_loss: 0.0018 - val_accuracy: 0.7319
Epoch 41/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0020 - accuracy: 0.7252 - val_loss: 0.0018 - val_accuracy: 0.7317
Epoch 42/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0019 - accuracy: 0.7207 - val_loss: 0.0019 - val_accuracy: 0.7360
Epoch 43/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0019 - accuracy: 0.7250 - val_loss: 0.0018 - val_accuracy: 0.7357
Epoch 44/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0020 - accuracy: 0.7206 - val_loss: 0.0018 - val_accuracy: 0.7274
Epoch 45/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0019 - accuracy: 0.7260 - val_loss: 0.0018 - val_accuracy: 0.7364
Epoch 46/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0019 - accuracy: 0.7235 - val_loss: 0.0017 - val_accuracy: 0.7351
Epoch 47/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0019 - accuracy: 0.7277 - val_loss: 0.0017 - val_accuracy: 0.7289
Epoch 48/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0019 - accuracy: 0.7216 - val_loss: 0.0018 - val_accuracy: 0.7388
Epoch 49/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0019 - accuracy: 0.7228 - val_loss: 0.0018 - val_accuracy: 0.7309
Epoch 50/100
230/230 [==============================] - 30s 126ms/step - loss: 0.0018 - accuracy: 0.7181 - val_loss: 0.0018 - val_accuracy: 0.7274
Epoch 51/100
230/230 [==============================] - 35s 151ms/step - loss: 0.0018 - accuracy: 0.7253 - val_loss: 0.0017 - val_accuracy: 0.7360
Epoch 52/100
230/230 [==============================] - 29s 125ms/step - loss: 0.0018 - accuracy: 0.7194 - val_loss: 0.0020 - val_accuracy: 0.7356
Epoch 53/100
230/230 [==============================] - 29s 125ms/step - loss: 0.0018 - accuracy: 0.7268 - val_loss: 0.0017 - val_accuracy: 0.7261
Epoch 54/100
230/230 [==============================] - 30s 127ms/step - loss: 0.0018 - accuracy: 0.7282 - val_loss: 0.0017 - val_accuracy: 0.7339
Epoch 55/100
230/230 [==============================] - 31s 132ms/step - loss: 0.0018 - accuracy: 0.7214 - val_loss: 0.0017 - val_accuracy: 0.7358
Epoch 56/100
230/230 [==============================] - 34s 143ms/step - loss: 0.0018 - accuracy: 0.7267 - val_loss: 0.0017 - val_accuracy: 0.7380
Epoch 57/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0018 - accuracy: 0.7234 - val_loss: 0.0017 - val_accuracy: 0.6977
Epoch 58/100
230/230 [==============================] - 29s 126ms/step - loss: 0.0017 - accuracy: 0.7276 - val_loss: 0.0016 - val_accuracy: 0.7140
Epoch 59/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0018 - accuracy: 0.7221 - val_loss: 0.0016 - val_accuracy: 0.7325
Epoch 60/100
230/230 [==============================] - 30s 127ms/step - loss: 0.0017 - accuracy: 0.7296 - val_loss: 0.0016 - val_accuracy: 0.7388
Epoch 61/100
230/230 [==============================] - 30s 127ms/step - loss: 0.0017 - accuracy: 0.7274 - val_loss: 0.0016 - val_accuracy: 0.7435
Epoch 62/100
230/230 [==============================] - 30s 126ms/step - loss: 0.0017 - accuracy: 0.7266 - val_loss: 0.0017 - val_accuracy: 0.7214
Epoch 63/100
230/230 [==============================] - 29s 126ms/step - loss: 0.0017 - accuracy: 0.7297 - val_loss: 0.0017 - val_accuracy: 0.7407
Epoch 64/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0027 - accuracy: 0.6955 - val_loss: 0.0018 - val_accuracy: 0.7342
Epoch 65/100
230/230 [==============================] - 31s 133ms/step - loss: 0.0018 - accuracy: 0.7334 - val_loss: 0.0017 - val_accuracy: 0.7342
Epoch 66/100
230/230 [==============================] - 33s 137ms/step - loss: 0.0017 - accuracy: 0.7301 - val_loss: 0.0017 - val_accuracy: 0.7108
Epoch 67/100
230/230 [==============================] - 35s 150ms/step - loss: 0.0017 - accuracy: 0.7290 - val_loss: 0.0016 - val_accuracy: 0.7335
Epoch 68/100
230/230 [==============================] - 31s 131ms/step - loss: 0.0017 - accuracy: 0.7292 - val_loss: 0.0017 - val_accuracy: 0.6722
Epoch 69/100
230/230 [==============================] - 35s 151ms/step - loss: 0.0017 - accuracy: 0.7274 - val_loss: 0.0016 - val_accuracy: 0.7292
Epoch 70/100
230/230 [==============================] - 32s 137ms/step - loss: 0.0017 - accuracy: 0.7285 - val_loss: 0.0016 - val_accuracy: 0.7349
Epoch 71/100
230/230 [==============================] - 32s 134ms/step - loss: 0.0017 - accuracy: 0.7325 - val_loss: 0.0016 - val_accuracy: 0.7262
Epoch 72/100
230/230 [==============================] - 35s 149ms/step - loss: 0.0017 - accuracy: 0.7322 - val_loss: 0.0016 - val_accuracy: 0.7108
Epoch 73/100
230/230 [==============================] - 29s 120ms/step - loss: 0.0016 - accuracy: 0.7335 - val_loss: 0.0016 - val_accuracy: 0.7195
Epoch 74/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0017 - accuracy: 0.7316 - val_loss: 0.0019 - val_accuracy: 0.7385
Epoch 75/100
230/230 [==============================] - 33s 143ms/step - loss: 0.0017 - accuracy: 0.7316 - val_loss: 0.0016 - val_accuracy: 0.7424
Epoch 76/100
230/230 [==============================] - 33s 141ms/step - loss: 0.0016 - accuracy: 0.7340 - val_loss: 0.0016 - val_accuracy: 0.7296
Epoch 77/100
230/230 [==============================] - 28s 120ms/step - loss: 0.0016 - accuracy: 0.7285 - val_loss: 0.0015 - val_accuracy: 0.7435
Epoch 78/100
230/230 [==============================] - 33s 138ms/step - loss: 0.0016 - accuracy: 0.7309 - val_loss: 0.0015 - val_accuracy: 0.7456
Epoch 79/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0016 - accuracy: 0.7317 - val_loss: 0.0016 - val_accuracy: 0.7341
Epoch 80/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0016 - accuracy: 0.7335 - val_loss: 0.0016 - val_accuracy: 0.7461
Epoch 81/100
230/230 [==============================] - 33s 141ms/step - loss: 0.0016 - accuracy: 0.7324 - val_loss: 0.0016 - val_accuracy: 0.7462
Epoch 82/100
230/230 [==============================] - 33s 142ms/step - loss: 0.0016 - accuracy: 0.7330 - val_loss: 0.0015 - val_accuracy: 0.7247
Epoch 83/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0016 - accuracy: 0.7356 - val_loss: 0.0015 - val_accuracy: 0.7178
Epoch 84/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0016 - accuracy: 0.7325 - val_loss: 0.0015 - val_accuracy: 0.7451
Epoch 85/100
230/230 [==============================] - 33s 141ms/step - loss: 0.0016 - accuracy: 0.7331 - val_loss: 0.0015 - val_accuracy: 0.7297
Epoch 86/100
230/230 [==============================] - 33s 140ms/step - loss: 0.0016 - accuracy: 0.7323 - val_loss: 0.0015 - val_accuracy: 0.7372
Epoch 87/100
230/230 [==============================] - 28s 120ms/step - loss: 0.0016 - accuracy: 0.7315 - val_loss: 0.0015 - val_accuracy: 0.7310
Epoch 88/100
230/230 [==============================] - 34s 144ms/step - loss: 0.0015 - accuracy: 0.7356 - val_loss: 0.0015 - val_accuracy: 0.7453
Epoch 89/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0015 - accuracy: 0.7350 - val_loss: 0.0015 - val_accuracy: 0.7411
Epoch 90/100
230/230 [==============================] - 28s 118ms/step - loss: 0.0016 - accuracy: 0.7339 - val_loss: 0.0016 - val_accuracy: 0.7138
Epoch 91/100
230/230 [==============================] - 29s 122ms/step - loss: 0.0015 - accuracy: 0.7339 - val_loss: 0.0015 - val_accuracy: 0.7438
Epoch 92/100
230/230 [==============================] - 28s 120ms/step - loss: 0.0015 - accuracy: 0.7313 - val_loss: 0.0014 - val_accuracy: 0.7411
Epoch 93/100
230/230 [==============================] - 32s 138ms/step - loss: 0.0015 - accuracy: 0.7343 - val_loss: 0.0015 - val_accuracy: 0.7131
Epoch 94/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0016 - accuracy: 0.7287 - val_loss: 0.0017 - val_accuracy: 0.7380
Epoch 95/100
230/230 [==============================] - 29s 123ms/step - loss: 0.0015 - accuracy: 0.7335 - val_loss: 0.0016 - val_accuracy: 0.6804
Epoch 96/100
230/230 [==============================] - 28s 118ms/step - loss: 0.0015 - accuracy: 0.7403 - val_loss: 0.0015 - val_accuracy: 0.7195
Epoch 97/100
230/230 [==============================] - 28s 118ms/step - loss: 0.0015 - accuracy: 0.7346 - val_loss: 0.0015 - val_accuracy: 0.7230
Epoch 98/100
230/230 [==============================] - 32s 136ms/step - loss: 0.0015 - accuracy: 0.7350 - val_loss: 0.0015 - val_accuracy: 0.7528
Epoch 99/100
230/230 [==============================] - 28s 120ms/step - loss: 0.0015 - accuracy: 0.7355 - val_loss: 0.0014 - val_accuracy: 0.7440
Epoch 100/100
230/230 [==============================] - 28s 121ms/step - loss: 0.0015 - accuracy: 0.7360 - val_loss: 0.0014 - val_accuracy: 0.7495
In [68]:
# Representación del loss
mostrar_graficas(entrenamiento_autoencoder)

4.2. Evaluación del autoencoder¶

La evaluación del modelo obtenido puede hacerse en este caso tanto de forma cuantitativa (calculando el MSE entre las imágenes originales y reconstruídas del conjunto de test) como cualitativa (mostrando imágenes originales y reconstruídas).

Ejercicio [1 punto]: Realizar las siguientes operaciones para evaluar las prestaciones del modelo obtenido:
  • Partiendo del conjunto de test obtenido en el primer apartado de la practica:
    • Llevar a cabo el reescalado de los datos utilizando la capa normalization_layer tal y como se ha hecho con los conjuntos de entrenamiento y test al inicio de este bloque.
    • Generar el conjunto de datos test_data_auto en el que las imágenes sean también el objetivo y substituyan a las etiquetas.
    </li>
  • Realizar la evaluación del modelo una vez ha finalizado el entrenamiento para mostrar la pérdida y la precisión final a partir de los datos de test.
  • Imprimir por pantalla 4 parejas de imágenes (original y reconstruída). Nota: a la hora de representar las imágenes correctamente, recordad que su rango dinámico deben ser números enteros entre 0 y 255.
  • </ul> Preguntas: ¿Consideras que la reconstrucción es adecuada? ¿Qué ratio de compresión se consigue con este autoencoder? Consideramos como ratio de compresión la relación entre el tamaño original de la imagen (224,224,3) y el de la representación más perqueña que llega a hacer el codificador (tamaño de la salida de su última capa).

In [69]:
# Normalización de los datos
normalization_layer = Rescaling(1./255)
normalized_test_data = test_data.map(lambda x, y: (normalization_layer(x), y))
test_data_auto = normalized_test_data.map(lambda x, y: (x, x))
image_batch, label_batch = iter(test_data_auto).get_next()
print("Las dimensiones de un batch de imágenes es: {}".format(image_batch.shape))
print("Las dimensiones de un batch de etiquetas es: {}".format(label_batch.shape))
first_image = image_batch[0]
print("En la primera imagen los valores mínimo y máximo son {} y {}, respectivamente"
      .format(np.min(first_image),np.max(first_image)))
Las dimensiones de un batch de imágenes es: (32, 224, 224, 3)
Las dimensiones de un batch de etiquetas es: (32, 224, 224, 3)
En la primera imagen los valores mínimo y máximo son 0.6426967978477478 y 0.9833736419677734, respectivamente
In [70]:
# Evaluación del modelo
test_loss, test_acc = modelo_autoencoder.evaluate(test_data_auto)

print("\nTiempo de entrenamiento:", end_time - start_time)
print('Pérdida en el conjunto de test:', test_loss)
print('Precisión en el conjunto de test:', test_acc)
33/33 [==============================] - 3s 79ms/step - loss: 0.0014 - accuracy: 0.7513

Tiempo de entrenamiento: 3535.9279289245605
Pérdida en el conjunto de test: 0.0014285397483035922
Precisión en el conjunto de test: 0.7512709498405457
In [71]:
# Visualización de los datos

n = 4  # número de parejas de imágenes a mostrar
plt.figure(figsize=(15, 6*n))
for i, (image, label) in enumerate(test_data_auto.take(n)):
    # imagen original
    ax = plt.subplot(n, 2, 2*i+1)
    plt.imshow(np.array(image[0]* 255, dtype=int))
    plt.title('Original')
    plt.axis('off')
    # imagen reconstruida
    ax = plt.subplot(n, 2, 2*i+2)
    reconstructed = modelo_autoencoder.predict(image)[0]
    plt.imshow(np.array(reconstructed* 255, dtype=int))
    plt.title('Reconstruida')
    plt.axis('off')
plt.show()
1/1 [==============================] - 0s 306ms/step
1/1 [==============================] - 0s 49ms/step
1/1 [==============================] - 0s 38ms/step
1/1 [==============================] - 0s 29ms/step
Comentarios:

Las respuestas a las preguntas planteadas son: * ¿Consideras que la reconstrucción es adecuada? Si, tenemos una precisión del 75,12% y a nivel visual se muestra bastante parecida la imagen reconstruida de la original. Por lo que considero que la reconstrucción es adecuada. * ¿Qué ratio de compresión se consigue con este autoencoder? Si la entrada tiene una dimensión de 224x224x3, y la capa de salida del codificador tiene una dimensión de 28x28x64, entonces el ratio de compresión sería: (224 * 224 * 3) / (28 * 28 * 64) = 37.29

5. Red VGG16 y transfer learning (2 puntos)¶

Las redes neuronales convolucionales profundas nos brindan la posibilidad de mejorar la capacidad de aprendizaje de un modelo. Algunas arquitecturas comunes, pueden incluir cientos de capas convolucionales. No obstante, entrenar estas arquitecturas desde cero puede resultar costoso tanto en términos de tiempo como de recursos, además de requerir conjuntos de datos bastante grandes.

5.1. Transfer Learning¶

En este apartado, aplicaremos transfer learning con el fin de ahorrarnos parte de dicho entrenamiento. Esta metodología consiste en aprovechar los pesos de un modelo entrenado en otra base de datos y para otra tarea. En concreto, utilizaremos el modelo VGG16 preentrenado en Imagenet, y lo adaptaremos para clasificar las 21 categorías de nuestra base de datos. En la versión de VGG16 de keras existe la opción de cargar los pesos entrenados en Imagenet sin las 3 capas totalmente conectadas de la parte final de la red (opción include_top = False), nosotros substituiremos esas 3 capas y reentrenaremos el conjunto con el resto de pesos congelados.

Para reutilizar el modelo correctamente es necesario preprocesar los datos tal y como se hizo durante el entrenamiento en la base de datos original. Keras nos facilita aplicar la normalización en el caso de modelos preentrenados; para el caso de VGG16 revisar la documentación de prepocess_input (tened en cuenta que la función se aplica sobre imágenes con rango dinámico de 0 a 255).

Ejercicio[1 punto]: Implementa una red siguiendo los siguientes pasos:
  • Partir del modelo VGG16 con los pesos entrenados en Imagenet y congelarlos
  • Substituir las 3 últimas capas completamente conectadas por 3 capas nuevas: las 2 primeras de 50 y 20 neuronas respectivamente con activación ReLU, y una última capa con el número de neuronas adecuado para llevar a cabo la tarea de clasificación sobre nuestra base de datos y la función de activación adecuada.
Compilar y entrenar el modelo siguiendo las siguientes indicaciones:
  • Utilizar el optimizador Adam con learning rate de 0.0001.
  • Entrenar durante 100 épocas utilizando EarlyStopping con una persistencia de 10 épocas, monitorizando la accuracy en el conjunto de validación, y guardando los pesos que mejor resultado hayan obtenido.
  • Monitorear la métrica accuracy durante entrenamiento y validación.
  • Mostrar las gráficas de accuracy y loss. En cada gráfica debe visualizarse la curva de entrenamiento y la de validación.
  • Realizar la evaluación del modelo una vez ha finalizado el entrenamiento para mostrar la pérdida y la precisión final a partir de los datos de test.
Preguntas a responder: ¿Cúal es el número de parámetros a entrenar? ¿y el tiempo de entrenamiento? ¿Qué precisión se obtiene con este modelo? Comenta los resultados.
In [16]:
from tensorflow.keras.applications.vgg16 import VGG16
from tensorflow.keras.applications.vgg16 import preprocess_input
from tensorflow.keras.preprocessing.image import ImageDataGenerator

## Loading VGG16 model
vgg = VGG16(weights='imagenet', include_top=False, input_shape=(224, 224, 3))

for layer in vgg.layers:
    layer.trainable = False
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/vgg16/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5
58889256/58889256 [==============================] - 4s 0us/step
In [17]:
# Definición de la red

# Substituir últimas capas completamente conectadas
flatten = Flatten()(vgg.output)
fc1 = Dense(50, activation='relu')(flatten)
fc2 = Dense(20, activation='relu')(fc1)
output = Dense(21, activation='softmax')(fc2)

# Crear modelo
modelo_VGG = Model(inputs=vgg.input, outputs=output)
In [18]:
# Compilación de la red
opt = Adam(learning_rate=0.0001)
modelo_VGG.compile(optimizer=opt, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
In [19]:
# Definir EarlyStopping y ModelCheckpoint
early_stop = tf.keras.callbacks.EarlyStopping(monitor='val_accuracy', patience=10, verbose=1)
best_model = tf.keras.callbacks.ModelCheckpoint('best_model.h5', monitor='val_accuracy', save_best_only=True, verbose=1)
In [20]:
# Entrenamiento de la red
start_time = time.time()
entrenamiento_VGG = modelo_VGG.fit(train_data, epochs=100, validation_data=val_data, callbacks=[early_stop, best_model])
end_time = time.time()
Epoch 1/100
230/230 [==============================] - ETA: 0s - loss: 2.6452 - accuracy: 0.3216
Epoch 1: val_accuracy improved from -inf to 0.55667, saving model to best_model.h5
230/230 [==============================] - 35s 134ms/step - loss: 2.6452 - accuracy: 0.3216 - val_loss: 1.5963 - val_accuracy: 0.5567
Epoch 2/100
230/230 [==============================] - ETA: 0s - loss: 0.8850 - accuracy: 0.7320
Epoch 2: val_accuracy improved from 0.55667 to 0.70857, saving model to best_model.h5
230/230 [==============================] - 28s 118ms/step - loss: 0.8850 - accuracy: 0.7320 - val_loss: 1.0719 - val_accuracy: 0.7086
Epoch 3/100
230/230 [==============================] - ETA: 0s - loss: 0.3207 - accuracy: 0.9093
Epoch 3: val_accuracy improved from 0.70857 to 0.75857, saving model to best_model.h5
230/230 [==============================] - 27s 115ms/step - loss: 0.3207 - accuracy: 0.9093 - val_loss: 0.9419 - val_accuracy: 0.7586
Epoch 4/100
230/230 [==============================] - ETA: 0s - loss: 0.1353 - accuracy: 0.9695
Epoch 4: val_accuracy improved from 0.75857 to 0.78000, saving model to best_model.h5
230/230 [==============================] - 27s 115ms/step - loss: 0.1353 - accuracy: 0.9695 - val_loss: 0.9114 - val_accuracy: 0.7800
Epoch 5/100
230/230 [==============================] - ETA: 0s - loss: 0.0622 - accuracy: 0.9880
Epoch 5: val_accuracy improved from 0.78000 to 0.78381, saving model to best_model.h5
230/230 [==============================] - 26s 112ms/step - loss: 0.0622 - accuracy: 0.9880 - val_loss: 0.9547 - val_accuracy: 0.7838
Epoch 6/100
230/230 [==============================] - ETA: 0s - loss: 0.0325 - accuracy: 0.9956
Epoch 6: val_accuracy improved from 0.78381 to 0.79905, saving model to best_model.h5
230/230 [==============================] - 27s 117ms/step - loss: 0.0325 - accuracy: 0.9956 - val_loss: 0.9345 - val_accuracy: 0.7990
Epoch 7/100
230/230 [==============================] - ETA: 0s - loss: 0.0200 - accuracy: 0.9967
Epoch 7: val_accuracy did not improve from 0.79905
230/230 [==============================] - 28s 119ms/step - loss: 0.0200 - accuracy: 0.9967 - val_loss: 0.9353 - val_accuracy: 0.7967
Epoch 8/100
230/230 [==============================] - ETA: 0s - loss: 0.0103 - accuracy: 0.9989
Epoch 8: val_accuracy improved from 0.79905 to 0.80238, saving model to best_model.h5
230/230 [==============================] - 27s 113ms/step - loss: 0.0103 - accuracy: 0.9989 - val_loss: 0.9400 - val_accuracy: 0.8024
Epoch 9/100
230/230 [==============================] - ETA: 0s - loss: 0.0065 - accuracy: 0.9995
Epoch 9: val_accuracy improved from 0.80238 to 0.80476, saving model to best_model.h5
230/230 [==============================] - 27s 115ms/step - loss: 0.0065 - accuracy: 0.9995 - val_loss: 0.9531 - val_accuracy: 0.8048
Epoch 10/100
230/230 [==============================] - ETA: 0s - loss: 0.0044 - accuracy: 0.9997
Epoch 10: val_accuracy improved from 0.80476 to 0.80857, saving model to best_model.h5
230/230 [==============================] - 28s 119ms/step - loss: 0.0044 - accuracy: 0.9997 - val_loss: 0.9569 - val_accuracy: 0.8086
Epoch 11/100
230/230 [==============================] - ETA: 0s - loss: 0.0030 - accuracy: 1.0000
Epoch 11: val_accuracy did not improve from 0.80857
230/230 [==============================] - 27s 114ms/step - loss: 0.0030 - accuracy: 1.0000 - val_loss: 0.9617 - val_accuracy: 0.8086
Epoch 12/100
230/230 [==============================] - ETA: 0s - loss: 0.0023 - accuracy: 1.0000
Epoch 12: val_accuracy improved from 0.80857 to 0.80952, saving model to best_model.h5
230/230 [==============================] - 27s 116ms/step - loss: 0.0023 - accuracy: 1.0000 - val_loss: 0.9659 - val_accuracy: 0.8095
Epoch 13/100
230/230 [==============================] - ETA: 0s - loss: 0.0018 - accuracy: 1.0000
Epoch 13: val_accuracy did not improve from 0.80952
230/230 [==============================] - 27s 114ms/step - loss: 0.0018 - accuracy: 1.0000 - val_loss: 0.9701 - val_accuracy: 0.8086
Epoch 14/100
230/230 [==============================] - ETA: 0s - loss: 0.0015 - accuracy: 1.0000
Epoch 14: val_accuracy improved from 0.80952 to 0.81000, saving model to best_model.h5
230/230 [==============================] - 28s 118ms/step - loss: 0.0015 - accuracy: 1.0000 - val_loss: 0.9728 - val_accuracy: 0.8100
Epoch 15/100
230/230 [==============================] - ETA: 0s - loss: 0.0012 - accuracy: 1.0000
Epoch 15: val_accuracy improved from 0.81000 to 0.81048, saving model to best_model.h5
230/230 [==============================] - 28s 121ms/step - loss: 0.0012 - accuracy: 1.0000 - val_loss: 0.9781 - val_accuracy: 0.8105
Epoch 16/100
230/230 [==============================] - ETA: 0s - loss: 0.0010 - accuracy: 1.0000
Epoch 16: val_accuracy did not improve from 0.81048
230/230 [==============================] - 28s 121ms/step - loss: 0.0010 - accuracy: 1.0000 - val_loss: 0.9814 - val_accuracy: 0.8105
Epoch 17/100
230/230 [==============================] - ETA: 0s - loss: 8.7704e-04 - accuracy: 1.0000
Epoch 17: val_accuracy improved from 0.81048 to 0.81238, saving model to best_model.h5
230/230 [==============================] - 28s 119ms/step - loss: 8.7704e-04 - accuracy: 1.0000 - val_loss: 0.9856 - val_accuracy: 0.8124
Epoch 18/100
230/230 [==============================] - ETA: 0s - loss: 7.3961e-04 - accuracy: 1.0000
Epoch 18: val_accuracy improved from 0.81238 to 0.81381, saving model to best_model.h5
230/230 [==============================] - 28s 116ms/step - loss: 7.3961e-04 - accuracy: 1.0000 - val_loss: 0.9924 - val_accuracy: 0.8138
Epoch 19/100
230/230 [==============================] - ETA: 0s - loss: 6.3542e-04 - accuracy: 1.0000
Epoch 19: val_accuracy did not improve from 0.81381
230/230 [==============================] - 28s 118ms/step - loss: 6.3542e-04 - accuracy: 1.0000 - val_loss: 0.9976 - val_accuracy: 0.8138
Epoch 20/100
230/230 [==============================] - ETA: 0s - loss: 5.3522e-04 - accuracy: 1.0000
Epoch 20: val_accuracy improved from 0.81381 to 0.81571, saving model to best_model.h5
230/230 [==============================] - 27s 113ms/step - loss: 5.3522e-04 - accuracy: 1.0000 - val_loss: 1.0025 - val_accuracy: 0.8157
Epoch 21/100
230/230 [==============================] - ETA: 0s - loss: 4.9257e-04 - accuracy: 1.0000
Epoch 21: val_accuracy did not improve from 0.81571
230/230 [==============================] - 27s 114ms/step - loss: 4.9257e-04 - accuracy: 1.0000 - val_loss: 1.0275 - val_accuracy: 0.8133
Epoch 22/100
230/230 [==============================] - ETA: 0s - loss: 8.0284e-04 - accuracy: 0.9999
Epoch 22: val_accuracy did not improve from 0.81571
230/230 [==============================] - 31s 131ms/step - loss: 8.0284e-04 - accuracy: 0.9999 - val_loss: 1.0382 - val_accuracy: 0.8148
Epoch 23/100
230/230 [==============================] - ETA: 0s - loss: 5.7824e-04 - accuracy: 1.0000
Epoch 23: val_accuracy improved from 0.81571 to 0.81762, saving model to best_model.h5
230/230 [==============================] - 28s 119ms/step - loss: 5.7824e-04 - accuracy: 1.0000 - val_loss: 1.0006 - val_accuracy: 0.8176
Epoch 24/100
230/230 [==============================] - ETA: 0s - loss: 0.1472 - accuracy: 0.9566
Epoch 24: val_accuracy did not improve from 0.81762
230/230 [==============================] - 27s 115ms/step - loss: 0.1472 - accuracy: 0.9566 - val_loss: 1.0879 - val_accuracy: 0.8052
Epoch 25/100
230/230 [==============================] - ETA: 0s - loss: 0.1475 - accuracy: 0.9642
Epoch 25: val_accuracy did not improve from 0.81762
230/230 [==============================] - 27s 114ms/step - loss: 0.1475 - accuracy: 0.9642 - val_loss: 1.0843 - val_accuracy: 0.8176
Epoch 26/100
230/230 [==============================] - ETA: 0s - loss: 0.0376 - accuracy: 0.9884
Epoch 26: val_accuracy improved from 0.81762 to 0.84238, saving model to best_model.h5
230/230 [==============================] - 31s 130ms/step - loss: 0.0376 - accuracy: 0.9884 - val_loss: 0.9634 - val_accuracy: 0.8424
Epoch 27/100
230/230 [==============================] - ETA: 0s - loss: 0.0112 - accuracy: 0.9981
Epoch 27: val_accuracy improved from 0.84238 to 0.85048, saving model to best_model.h5
230/230 [==============================] - 28s 118ms/step - loss: 0.0112 - accuracy: 0.9981 - val_loss: 0.9572 - val_accuracy: 0.8505
Epoch 28/100
230/230 [==============================] - ETA: 0s - loss: 0.0036 - accuracy: 0.9995
Epoch 28: val_accuracy improved from 0.85048 to 0.85238, saving model to best_model.h5
230/230 [==============================] - 27s 115ms/step - loss: 0.0036 - accuracy: 0.9995 - val_loss: 0.8783 - val_accuracy: 0.8524
Epoch 29/100
230/230 [==============================] - ETA: 0s - loss: 6.3644e-04 - accuracy: 1.0000
Epoch 29: val_accuracy improved from 0.85238 to 0.85905, saving model to best_model.h5
230/230 [==============================] - 27s 115ms/step - loss: 6.3644e-04 - accuracy: 1.0000 - val_loss: 0.8754 - val_accuracy: 0.8590
Epoch 30/100
230/230 [==============================] - ETA: 0s - loss: 4.2551e-04 - accuracy: 1.0000
Epoch 30: val_accuracy did not improve from 0.85905
230/230 [==============================] - 27s 114ms/step - loss: 4.2551e-04 - accuracy: 1.0000 - val_loss: 0.8827 - val_accuracy: 0.8590
Epoch 31/100
230/230 [==============================] - ETA: 0s - loss: 3.4693e-04 - accuracy: 1.0000
Epoch 31: val_accuracy did not improve from 0.85905
230/230 [==============================] - 28s 117ms/step - loss: 3.4693e-04 - accuracy: 1.0000 - val_loss: 0.8882 - val_accuracy: 0.8576
Epoch 32/100
230/230 [==============================] - ETA: 0s - loss: 2.9336e-04 - accuracy: 1.0000
Epoch 32: val_accuracy did not improve from 0.85905
230/230 [==============================] - 27s 114ms/step - loss: 2.9336e-04 - accuracy: 1.0000 - val_loss: 0.8941 - val_accuracy: 0.8576
Epoch 33/100
230/230 [==============================] - ETA: 0s - loss: 2.5143e-04 - accuracy: 1.0000
Epoch 33: val_accuracy did not improve from 0.85905
230/230 [==============================] - 26s 113ms/step - loss: 2.5143e-04 - accuracy: 1.0000 - val_loss: 0.9007 - val_accuracy: 0.8562
Epoch 34/100
230/230 [==============================] - ETA: 0s - loss: 2.1907e-04 - accuracy: 1.0000
Epoch 34: val_accuracy did not improve from 0.85905
230/230 [==============================] - 27s 114ms/step - loss: 2.1907e-04 - accuracy: 1.0000 - val_loss: 0.9063 - val_accuracy: 0.8562
Epoch 35/100
230/230 [==============================] - ETA: 0s - loss: 1.9236e-04 - accuracy: 1.0000
Epoch 35: val_accuracy did not improve from 0.85905
230/230 [==============================] - 28s 118ms/step - loss: 1.9236e-04 - accuracy: 1.0000 - val_loss: 0.9120 - val_accuracy: 0.8552
Epoch 36/100
230/230 [==============================] - ETA: 0s - loss: 1.6989e-04 - accuracy: 1.0000
Epoch 36: val_accuracy did not improve from 0.85905
230/230 [==============================] - 27s 114ms/step - loss: 1.6989e-04 - accuracy: 1.0000 - val_loss: 0.9174 - val_accuracy: 0.8567
Epoch 37/100
230/230 [==============================] - ETA: 0s - loss: 1.5055e-04 - accuracy: 1.0000
Epoch 37: val_accuracy did not improve from 0.85905
230/230 [==============================] - 27s 116ms/step - loss: 1.5055e-04 - accuracy: 1.0000 - val_loss: 0.9224 - val_accuracy: 0.8552
Epoch 38/100
230/230 [==============================] - ETA: 0s - loss: 1.3416e-04 - accuracy: 1.0000
Epoch 38: val_accuracy did not improve from 0.85905
230/230 [==============================] - 28s 118ms/step - loss: 1.3416e-04 - accuracy: 1.0000 - val_loss: 0.9272 - val_accuracy: 0.8548
Epoch 39/100
230/230 [==============================] - ETA: 0s - loss: 1.1958e-04 - accuracy: 1.0000
Epoch 39: val_accuracy did not improve from 0.85905
230/230 [==============================] - 31s 130ms/step - loss: 1.1958e-04 - accuracy: 1.0000 - val_loss: 0.9319 - val_accuracy: 0.8548
Epoch 39: early stopping
In [21]:
# Representación del loss
mostrar_graficas(entrenamiento_VGG)
In [22]:
#Información del modelo
modelo_VGG.summary() 
Model: "model_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_2 (InputLayer)        [(None, 224, 224, 3)]     0         
                                                                 
 block1_conv1 (Conv2D)       (None, 224, 224, 64)      1792      
                                                                 
 block1_conv2 (Conv2D)       (None, 224, 224, 64)      36928     
                                                                 
 block1_pool (MaxPooling2D)  (None, 112, 112, 64)      0         
                                                                 
 block2_conv1 (Conv2D)       (None, 112, 112, 128)     73856     
                                                                 
 block2_conv2 (Conv2D)       (None, 112, 112, 128)     147584    
                                                                 
 block2_pool (MaxPooling2D)  (None, 56, 56, 128)       0         
                                                                 
 block3_conv1 (Conv2D)       (None, 56, 56, 256)       295168    
                                                                 
 block3_conv2 (Conv2D)       (None, 56, 56, 256)       590080    
                                                                 
 block3_conv3 (Conv2D)       (None, 56, 56, 256)       590080    
                                                                 
 block3_pool (MaxPooling2D)  (None, 28, 28, 256)       0         
                                                                 
 block4_conv1 (Conv2D)       (None, 28, 28, 512)       1180160   
                                                                 
 block4_conv2 (Conv2D)       (None, 28, 28, 512)       2359808   
                                                                 
 block4_conv3 (Conv2D)       (None, 28, 28, 512)       2359808   
                                                                 
 block4_pool (MaxPooling2D)  (None, 14, 14, 512)       0         
                                                                 
 block5_conv1 (Conv2D)       (None, 14, 14, 512)       2359808   
                                                                 
 block5_conv2 (Conv2D)       (None, 14, 14, 512)       2359808   
                                                                 
 block5_conv3 (Conv2D)       (None, 14, 14, 512)       2359808   
                                                                 
 block5_pool (MaxPooling2D)  (None, 7, 7, 512)         0         
                                                                 
 flatten (Flatten)           (None, 25088)             0         
                                                                 
 dense_2 (Dense)             (None, 50)                1254450   
                                                                 
 dense_3 (Dense)             (None, 20)                1020      
                                                                 
 dense_4 (Dense)             (None, 21)                441       
                                                                 
=================================================================
Total params: 15,970,599
Trainable params: 1,255,911
Non-trainable params: 14,714,688
_________________________________________________________________
In [23]:
# Resultados
test_loss, test_acc = modelo_VGG.evaluate(test_data)

print("\nTiempo de entrenamiento:",end_time - start_time)
print('Pérdida en el conjunto de test:', test_loss)
print('Precisión en el conjunto de test:', test_acc)
33/33 [==============================] - 8s 190ms/step - loss: 1.0031 - accuracy: 0.8610

Tiempo de entrenamiento: 1248.644618988037
Pérdida en el conjunto de test: 1.0031335353851318
Precisión en el conjunto de test: 0.8609523773193359
Comentarios:

Las respuestas a las preguntas planteadas son: * ¿Cúal es el número de parámetros a entrenar? 15,970,599 * ¿Y el tiempo de entrenamiento? El tiempo total de entrenamiento ha sido aproximadamente de 21 minutos * ¿Qué precisión se obtiene con este modelo? 86% Como se puede comprobar la precisión del modelo es muy superior a la de los modelos anteriores por lo que la tranferencia de conocimiento puede ser bastante util para este tipo de casos.

5.2. Fine-tunning¶

Una técnica frecuente, sobretodo cuando la red utilizada no es excesivamente grande (como es el caso de VGG16), para mejorar los resultados del transfer learning es el denominado fine-tunning, que consiste en reentrenar la red completa durante unas pocas épocas y con un learning rate muy pequeño.

Ejercicio[1 punto]: Volver a compilar el modelo con los siguientes cambios:
  • Descongelar los pesos del modelo VGG16 poniendo trainable=False (no confundir con traning=False).
Compilar y entrenar el modelo siguiendo las siguientes indicaciones:
  • Utilizar el optimizador Adam con learning rate de 0.00001.
  • Entrenar durante 10 épocas utilizando EarlyStopping con una persistencia de 10 épocas monitorizando la accuracy en el conjunto de validación, y guardando los pesos que mejor resultado hayan obtenido.
  • Monitorizar la métrica accuracy durante entrenamiento y validación.
  • Mostrar las gráficas de accuracy y loss. En cada gráfica debe visualizarse la curva de entrenamiento y la de validación.
  • Realizar la evaluación del modelo una vez ha finalizado el entrenamiento para mostrar la pérdida y la precisión final a partir de los datos de test.
Preguntas a responder: ¿Cúal es el número de parámetros a entrenar? ¿y el tiempo de entrenamiento? ¿Qué precisión se obtiene con este modelo? Comenta los resultados teniendo en cuenta el proceso global: transfer lerning + fine-tunning.
In [25]:
# Definición del modelo
modelo_VGG16 = VGG16(weights='imagenet', include_top=False, input_shape=(224, 224, 3))

# Congelamos los pesos del modelo
for layer in modelo_VGG16.layers:
    layer.trainable = True

new_modelo_VGG16 = Sequential()
new_modelo_VGG16.add(modelo_VGG16)
new_modelo_VGG16.add(Flatten())
new_modelo_VGG16.add(Dense(50, activation='relu'))
new_modelo_VGG16.add(Dense(20, activation='relu'))
new_modelo_VGG16.add(Dense(21, activation='softmax'))
In [26]:
# Compilación de la red
optimizer = Adam(learning_rate=0.00001)
new_modelo_VGG16.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
In [27]:
# Definir EarlyStopping y ModelCheckpoint
early_stopping = tf.keras.callbacks.EarlyStopping(monitor='val_accuracy', patience=10, verbose=1)
checkpoint = tf.keras.callbacks.ModelCheckpoint('best_model_ft.h5', monitor='val_accuracy', save_best_only=True, verbose=1)
In [28]:
# Entrenamiento
start_time = time.time()
entrenamiento_new_modelo_VGG16 = new_modelo_VGG16.fit(train_data, 
                                                      epochs=10, 
                                                      validation_data=val_data, 
                                                      callbacks=[early_stopping, checkpoint], 
                                                      verbose=1)
end_time = time.time()
Epoch 1/10
230/230 [==============================] - ETA: 0s - loss: 3.1590 - accuracy: 0.1072
Epoch 1: val_accuracy improved from -inf to 0.21810, saving model to best_model_ft.h5
230/230 [==============================] - 58s 240ms/step - loss: 3.1590 - accuracy: 0.1072 - val_loss: 2.6392 - val_accuracy: 0.2181
Epoch 2/10
230/230 [==============================] - ETA: 0s - loss: 2.2931 - accuracy: 0.3120
Epoch 2: val_accuracy improved from 0.21810 to 0.40667, saving model to best_model_ft.h5
230/230 [==============================] - 55s 237ms/step - loss: 2.2931 - accuracy: 0.3120 - val_loss: 1.9386 - val_accuracy: 0.4067
Epoch 3/10
230/230 [==============================] - ETA: 0s - loss: 1.3795 - accuracy: 0.5830
Epoch 3: val_accuracy improved from 0.40667 to 0.65762, saving model to best_model_ft.h5
230/230 [==============================] - 56s 240ms/step - loss: 1.3795 - accuracy: 0.5830 - val_loss: 1.1671 - val_accuracy: 0.6576
Epoch 4/10
230/230 [==============================] - ETA: 0s - loss: 0.7036 - accuracy: 0.7894
Epoch 4: val_accuracy improved from 0.65762 to 0.74095, saving model to best_model_ft.h5
230/230 [==============================] - 55s 236ms/step - loss: 0.7036 - accuracy: 0.7894 - val_loss: 0.9259 - val_accuracy: 0.7410
Epoch 5/10
230/230 [==============================] - ETA: 0s - loss: 0.3529 - accuracy: 0.8888
Epoch 5: val_accuracy improved from 0.74095 to 0.78905, saving model to best_model_ft.h5
230/230 [==============================] - 55s 236ms/step - loss: 0.3529 - accuracy: 0.8888 - val_loss: 0.8011 - val_accuracy: 0.7890
Epoch 6/10
230/230 [==============================] - ETA: 0s - loss: 0.1900 - accuracy: 0.9407
Epoch 6: val_accuracy improved from 0.78905 to 0.79333, saving model to best_model_ft.h5
230/230 [==============================] - 56s 239ms/step - loss: 0.1900 - accuracy: 0.9407 - val_loss: 0.9026 - val_accuracy: 0.7933
Epoch 7/10
230/230 [==============================] - ETA: 0s - loss: 0.1271 - accuracy: 0.9624
Epoch 7: val_accuracy improved from 0.79333 to 0.81952, saving model to best_model_ft.h5
230/230 [==============================] - 55s 235ms/step - loss: 0.1271 - accuracy: 0.9624 - val_loss: 0.7973 - val_accuracy: 0.8195
Epoch 8/10
230/230 [==============================] - ETA: 0s - loss: 0.0777 - accuracy: 0.9789
Epoch 8: val_accuracy improved from 0.81952 to 0.84429, saving model to best_model_ft.h5
230/230 [==============================] - 55s 236ms/step - loss: 0.0777 - accuracy: 0.9789 - val_loss: 0.7065 - val_accuracy: 0.8443
Epoch 9/10
230/230 [==============================] - ETA: 0s - loss: 0.0644 - accuracy: 0.9835
Epoch 9: val_accuracy improved from 0.84429 to 0.84952, saving model to best_model_ft.h5
230/230 [==============================] - 59s 255ms/step - loss: 0.0644 - accuracy: 0.9835 - val_loss: 0.7828 - val_accuracy: 0.8495
Epoch 10/10
230/230 [==============================] - ETA: 0s - loss: 0.0355 - accuracy: 0.9920
Epoch 10: val_accuracy improved from 0.84952 to 0.86048, saving model to best_model_ft.h5
230/230 [==============================] - 55s 237ms/step - loss: 0.0355 - accuracy: 0.9920 - val_loss: 0.7301 - val_accuracy: 0.8605
In [29]:
# Representación del loss
mostrar_graficas(entrenamiento_new_modelo_VGG16)
In [30]:
#Información del modelo
new_modelo_VGG16.summary() 
Model: "sequential_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 vgg16 (Functional)          (None, 7, 7, 512)         14714688  
                                                                 
 flatten_2 (Flatten)         (None, 25088)             0         
                                                                 
 dense_8 (Dense)             (None, 50)                1254450   
                                                                 
 dense_9 (Dense)             (None, 20)                1020      
                                                                 
 dense_10 (Dense)            (None, 21)                441       
                                                                 
=================================================================
Total params: 15,970,599
Trainable params: 15,970,599
Non-trainable params: 0
_________________________________________________________________
In [31]:
# Resultados
test_loss, test_acc = new_modelo_VGG16.evaluate(test_data)

print("\nTiempo de entrenamiento:", end_time - start_time)
print('Pérdida en el conjunto de test:', test_loss)
print('Precisión en el conjunto de test:', test_acc)
33/33 [==============================] - 4s 94ms/step - loss: 0.8095 - accuracy: 0.8543

Tiempo de entrenamiento: 717.4674685001373
Pérdida en el conjunto de test: 0.8094838857650757
Precisión en el conjunto de test: 0.854285717010498
Comentarios:

Las respuestas a las preguntas planteadas son: * ¿Cúal es el número de parámetros a entrenar? 15,970,599 * ¿Y el tiempo de entrenamiento? El tiempo total de entrenamiento ha sido aproximadamente de 12 minutos * ¿Qué precisión se obtiene con este modelo? 85,4% Teniendo en cuenta el proceso global de transfer learning y fine-tuning, podemos observar que este método suele ser efectivo para problemas de análisis de imágenes, viendo que tenemos una precisión bastante mayor que el resto de metodos, y que en los dos casos que hemos realizado, la precisión no ha variado mucho, pero siempre ha sido mejor que los otros casos.

6. Mejora de resultados (1 punto)¶

En este último apartado se deja libertad al alumno para conseguir, mediante el diseño de una red propia, unos mejores resultados en la tarea de clasificación.

Se valorarará la justificación de las elecciones realizadas.

Ejercicio[1 punto]: Implementar un modelo para llevar a cabo la tarea de clasificación:
  • Diseñar la arquitectura de la red
  • Compilar el modelo
  • Llevar a cabo el entrenamientio
  • Evaluar el modelo presentando las métricas y gráficas adecuadas
  • Comentar los resultados obtenidos
In [6]:
# Dimensiones de entrada de los datos
input_shape = (224, 224, 3)

# Capa de entrada
input_layer = Input(shape=input_shape)

# Capa de rescalado
rescale_layer = Rescaling(scale=1./255)(input_layer)

# Bloque extractor de características

## Capa 1
conv1_layer = Conv2D(filters=32, kernel_size=(3, 3), padding='same', activation='relu')(rescale_layer)
conv2_layer = Conv2D(filters=32, kernel_size=(3, 3), padding='same', activation='relu')(conv1_layer)
pool1_layer = MaxPooling2D(pool_size=(2, 2))(conv2_layer)

## Capa 2
conv3_layer = Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation='relu')(pool1_layer)
conv4_layer = Conv2D(filters=64, kernel_size=(3, 3), padding='same', activation='relu')(conv3_layer)
pool2_layer = MaxPooling2D(pool_size=(2, 2))(conv4_layer)

## Capa 3
conv5_layer = Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation='relu')(pool2_layer)
conv6_layer = Conv2D(filters=128, kernel_size=(3, 3), padding='same', activation='relu')(conv5_layer)
pool3_layer = MaxPooling2D(pool_size=(2, 2))(conv6_layer)

## Capa Global
global_pool_layer = GlobalAveragePooling2D()(pool3_layer)

# Clasificador final
dense1_layer = Dense(units=512, activation='relu')(global_pool_layer)
dropout_layer = Dropout(rate=0.5)(dense1_layer)

output_layer = Dense(units=21, activation='softmax')(dropout_layer)

# Crear modelo
modelo_final = Model(inputs=input_layer, outputs=output_layer)
In [7]:
# Compilar el modelo
modelo_final.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
In [8]:
# Definir EarlyStopping y ModelCheckpoint
early_stopping =  tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=10, verbose=1)
checkpoint = tf.keras.callbacks.ModelCheckpoint('best_model.h5', monitor='val_loss', save_best_only=True, verbose=1)
In [9]:
# Entrenar el modelo
start_time = time.time()
entrenamiento_modelo_final = modelo_final.fit(train_data, 
                                              epochs=100, 
                                              validation_data=val_data, 
                                              callbacks=[early_stopping, checkpoint])
end_time = time.time()
Epoch 1/100
230/230 [==============================] - ETA: 0s - loss: 3.0299 - accuracy: 0.0468
Epoch 1: val_loss improved from inf to 2.95095, saving model to best_model.h5
230/230 [==============================] - 50s 173ms/step - loss: 3.0299 - accuracy: 0.0468 - val_loss: 2.9509 - val_accuracy: 0.0767
Epoch 2/100
229/230 [============================>.] - ETA: 0s - loss: 2.6319 - accuracy: 0.1344
Epoch 2: val_loss improved from 2.95095 to 2.29867, saving model to best_model.h5
230/230 [==============================] - 30s 126ms/step - loss: 2.6317 - accuracy: 0.1350 - val_loss: 2.2987 - val_accuracy: 0.2367
Epoch 3/100
229/230 [============================>.] - ETA: 0s - loss: 2.1523 - accuracy: 0.2612
Epoch 3: val_loss improved from 2.29867 to 1.87961, saving model to best_model.h5
230/230 [==============================] - 28s 119ms/step - loss: 2.1512 - accuracy: 0.2614 - val_loss: 1.8796 - val_accuracy: 0.3843
Epoch 4/100
229/230 [============================>.] - ETA: 0s - loss: 1.8195 - accuracy: 0.3780
Epoch 4: val_loss improved from 1.87961 to 1.63593, saving model to best_model.h5
230/230 [==============================] - 29s 122ms/step - loss: 1.8199 - accuracy: 0.3780 - val_loss: 1.6359 - val_accuracy: 0.4481
Epoch 5/100
229/230 [============================>.] - ETA: 0s - loss: 1.5646 - accuracy: 0.4728
Epoch 5: val_loss improved from 1.63593 to 1.32883, saving model to best_model.h5
230/230 [==============================] - 30s 128ms/step - loss: 1.5638 - accuracy: 0.4732 - val_loss: 1.3288 - val_accuracy: 0.5586
Epoch 6/100
229/230 [============================>.] - ETA: 0s - loss: 1.3275 - accuracy: 0.5345
Epoch 6: val_loss did not improve from 1.32883
230/230 [==============================] - 28s 118ms/step - loss: 1.3278 - accuracy: 0.5347 - val_loss: 1.3628 - val_accuracy: 0.5276
Epoch 7/100
229/230 [============================>.] - ETA: 0s - loss: 1.1977 - accuracy: 0.5901
Epoch 7: val_loss improved from 1.32883 to 1.08108, saving model to best_model.h5
230/230 [==============================] - 29s 123ms/step - loss: 1.1962 - accuracy: 0.5903 - val_loss: 1.0811 - val_accuracy: 0.6467
Epoch 8/100
229/230 [============================>.] - ETA: 0s - loss: 1.0913 - accuracy: 0.6224
Epoch 8: val_loss improved from 1.08108 to 1.02929, saving model to best_model.h5
230/230 [==============================] - 29s 122ms/step - loss: 1.0910 - accuracy: 0.6226 - val_loss: 1.0293 - val_accuracy: 0.6557
Epoch 9/100
229/230 [============================>.] - ETA: 0s - loss: 0.9506 - accuracy: 0.6635
Epoch 9: val_loss improved from 1.02929 to 1.00183, saving model to best_model.h5
230/230 [==============================] - 29s 121ms/step - loss: 0.9501 - accuracy: 0.6638 - val_loss: 1.0018 - val_accuracy: 0.6581
Epoch 10/100
229/230 [============================>.] - ETA: 0s - loss: 0.9033 - accuracy: 0.6838
Epoch 10: val_loss improved from 1.00183 to 0.91614, saving model to best_model.h5
230/230 [==============================] - 29s 122ms/step - loss: 0.9023 - accuracy: 0.6838 - val_loss: 0.9161 - val_accuracy: 0.6976
Epoch 11/100
229/230 [============================>.] - ETA: 0s - loss: 0.8343 - accuracy: 0.7066
Epoch 11: val_loss improved from 0.91614 to 0.78828, saving model to best_model.h5
230/230 [==============================] - 29s 122ms/step - loss: 0.8339 - accuracy: 0.7067 - val_loss: 0.7883 - val_accuracy: 0.7414
Epoch 12/100
229/230 [============================>.] - ETA: 0s - loss: 0.8017 - accuracy: 0.7204
Epoch 12: val_loss improved from 0.78828 to 0.76631, saving model to best_model.h5
230/230 [==============================] - 28s 121ms/step - loss: 0.8007 - accuracy: 0.7208 - val_loss: 0.7663 - val_accuracy: 0.7529
Epoch 13/100
229/230 [============================>.] - ETA: 0s - loss: 0.7343 - accuracy: 0.7471
Epoch 13: val_loss improved from 0.76631 to 0.71314, saving model to best_model.h5
230/230 [==============================] - 29s 122ms/step - loss: 0.7338 - accuracy: 0.7475 - val_loss: 0.7131 - val_accuracy: 0.7700
Epoch 14/100
229/230 [============================>.] - ETA: 0s - loss: 0.6725 - accuracy: 0.7703
Epoch 14: val_loss improved from 0.71314 to 0.70099, saving model to best_model.h5
230/230 [==============================] - 29s 122ms/step - loss: 0.6728 - accuracy: 0.7703 - val_loss: 0.7010 - val_accuracy: 0.7676
Epoch 15/100
229/230 [============================>.] - ETA: 0s - loss: 0.6631 - accuracy: 0.7698
Epoch 15: val_loss improved from 0.70099 to 0.60506, saving model to best_model.h5
230/230 [==============================] - 28s 121ms/step - loss: 0.6622 - accuracy: 0.7702 - val_loss: 0.6051 - val_accuracy: 0.7967
Epoch 16/100
229/230 [============================>.] - ETA: 0s - loss: 0.6088 - accuracy: 0.7900
Epoch 16: val_loss improved from 0.60506 to 0.57974, saving model to best_model.h5
230/230 [==============================] - 28s 121ms/step - loss: 0.6086 - accuracy: 0.7901 - val_loss: 0.5797 - val_accuracy: 0.8024
Epoch 17/100
229/230 [============================>.] - ETA: 0s - loss: 0.5787 - accuracy: 0.7952
Epoch 17: val_loss did not improve from 0.57974
230/230 [==============================] - 28s 118ms/step - loss: 0.5792 - accuracy: 0.7952 - val_loss: 0.6617 - val_accuracy: 0.7819
Epoch 18/100
229/230 [============================>.] - ETA: 0s - loss: 0.5259 - accuracy: 0.8118
Epoch 18: val_loss did not improve from 0.57974
230/230 [==============================] - 33s 140ms/step - loss: 0.5255 - accuracy: 0.8120 - val_loss: 0.6086 - val_accuracy: 0.8062
Epoch 19/100
229/230 [============================>.] - ETA: 0s - loss: 0.5043 - accuracy: 0.8200
Epoch 19: val_loss did not improve from 0.57974
230/230 [==============================] - 28s 121ms/step - loss: 0.5038 - accuracy: 0.8201 - val_loss: 0.6178 - val_accuracy: 0.8029
Epoch 20/100
229/230 [============================>.] - ETA: 0s - loss: 0.5101 - accuracy: 0.8240
Epoch 20: val_loss did not improve from 0.57974
230/230 [==============================] - 29s 122ms/step - loss: 0.5102 - accuracy: 0.8241 - val_loss: 0.6056 - val_accuracy: 0.8190
Epoch 21/100
229/230 [============================>.] - ETA: 0s - loss: 0.4868 - accuracy: 0.8289
Epoch 21: val_loss did not improve from 0.57974
230/230 [==============================] - 29s 122ms/step - loss: 0.4867 - accuracy: 0.8288 - val_loss: 0.6139 - val_accuracy: 0.8071
Epoch 22/100
229/230 [============================>.] - ETA: 0s - loss: 0.4640 - accuracy: 0.8383
Epoch 22: val_loss improved from 0.57974 to 0.51141, saving model to best_model.h5
230/230 [==============================] - 28s 120ms/step - loss: 0.4638 - accuracy: 0.8382 - val_loss: 0.5114 - val_accuracy: 0.8424
Epoch 23/100
229/230 [============================>.] - ETA: 0s - loss: 0.4082 - accuracy: 0.8563
Epoch 23: val_loss did not improve from 0.51141
230/230 [==============================] - 33s 143ms/step - loss: 0.4081 - accuracy: 0.8559 - val_loss: 0.5660 - val_accuracy: 0.8224
Epoch 24/100
229/230 [============================>.] - ETA: 0s - loss: 0.4355 - accuracy: 0.8506
Epoch 24: val_loss did not improve from 0.51141
230/230 [==============================] - 29s 121ms/step - loss: 0.4346 - accuracy: 0.8509 - val_loss: 0.5882 - val_accuracy: 0.8143
Epoch 25/100
229/230 [============================>.] - ETA: 0s - loss: 0.4035 - accuracy: 0.8581
Epoch 25: val_loss did not improve from 0.51141
230/230 [==============================] - 28s 119ms/step - loss: 0.4035 - accuracy: 0.8582 - val_loss: 0.5619 - val_accuracy: 0.8333
Epoch 26/100
229/230 [============================>.] - ETA: 0s - loss: 0.3745 - accuracy: 0.8704
Epoch 26: val_loss improved from 0.51141 to 0.48655, saving model to best_model.h5
230/230 [==============================] - 28s 121ms/step - loss: 0.3741 - accuracy: 0.8705 - val_loss: 0.4866 - val_accuracy: 0.8600
Epoch 27/100
229/230 [============================>.] - ETA: 0s - loss: 0.3608 - accuracy: 0.8724
Epoch 27: val_loss improved from 0.48655 to 0.44667, saving model to best_model.h5
230/230 [==============================] - 28s 121ms/step - loss: 0.3600 - accuracy: 0.8728 - val_loss: 0.4467 - val_accuracy: 0.8595
Epoch 28/100
229/230 [============================>.] - ETA: 0s - loss: 0.3509 - accuracy: 0.8777
Epoch 28: val_loss did not improve from 0.44667
230/230 [==============================] - 28s 121ms/step - loss: 0.3515 - accuracy: 0.8776 - val_loss: 0.5956 - val_accuracy: 0.8229
Epoch 29/100
229/230 [============================>.] - ETA: 0s - loss: 0.3151 - accuracy: 0.8911
Epoch 29: val_loss did not improve from 0.44667
230/230 [==============================] - 28s 121ms/step - loss: 0.3147 - accuracy: 0.8912 - val_loss: 0.5146 - val_accuracy: 0.8510
Epoch 30/100
229/230 [============================>.] - ETA: 0s - loss: 0.3002 - accuracy: 0.8955
Epoch 30: val_loss did not improve from 0.44667
230/230 [==============================] - 28s 120ms/step - loss: 0.2998 - accuracy: 0.8955 - val_loss: 0.5361 - val_accuracy: 0.8486
Epoch 31/100
229/230 [============================>.] - ETA: 0s - loss: 0.2834 - accuracy: 0.9041
Epoch 31: val_loss did not improve from 0.44667
230/230 [==============================] - 29s 122ms/step - loss: 0.2838 - accuracy: 0.9038 - val_loss: 0.5531 - val_accuracy: 0.8210
Epoch 32/100
229/230 [============================>.] - ETA: 0s - loss: 0.2841 - accuracy: 0.9028
Epoch 32: val_loss did not improve from 0.44667
230/230 [==============================] - 29s 125ms/step - loss: 0.2841 - accuracy: 0.9030 - val_loss: 0.4708 - val_accuracy: 0.8614
Epoch 33/100
229/230 [============================>.] - ETA: 0s - loss: 0.2878 - accuracy: 0.8978
Epoch 33: val_loss improved from 0.44667 to 0.42972, saving model to best_model.h5
230/230 [==============================] - 31s 134ms/step - loss: 0.2875 - accuracy: 0.8981 - val_loss: 0.4297 - val_accuracy: 0.8714
Epoch 34/100
229/230 [============================>.] - ETA: 0s - loss: 0.2530 - accuracy: 0.9102
Epoch 34: val_loss improved from 0.42972 to 0.39075, saving model to best_model.h5
230/230 [==============================] - 34s 143ms/step - loss: 0.2527 - accuracy: 0.9103 - val_loss: 0.3908 - val_accuracy: 0.8862
Epoch 35/100
229/230 [============================>.] - ETA: 0s - loss: 0.2572 - accuracy: 0.9083
Epoch 35: val_loss did not improve from 0.39075
230/230 [==============================] - 33s 141ms/step - loss: 0.2570 - accuracy: 0.9083 - val_loss: 0.5409 - val_accuracy: 0.8305
Epoch 36/100
229/230 [============================>.] - ETA: 0s - loss: 0.2424 - accuracy: 0.9162
Epoch 36: val_loss did not improve from 0.39075
230/230 [==============================] - 31s 130ms/step - loss: 0.2429 - accuracy: 0.9161 - val_loss: 0.3995 - val_accuracy: 0.8852
Epoch 37/100
229/230 [============================>.] - ETA: 0s - loss: 0.2216 - accuracy: 0.9207
Epoch 37: val_loss did not improve from 0.39075
230/230 [==============================] - 29s 122ms/step - loss: 0.2211 - accuracy: 0.9210 - val_loss: 0.4551 - val_accuracy: 0.8681
Epoch 38/100
229/230 [============================>.] - ETA: 0s - loss: 0.2204 - accuracy: 0.9221
Epoch 38: val_loss did not improve from 0.39075
230/230 [==============================] - 30s 127ms/step - loss: 0.2199 - accuracy: 0.9223 - val_loss: 0.4085 - val_accuracy: 0.8829
Epoch 39/100
229/230 [============================>.] - ETA: 0s - loss: 0.2217 - accuracy: 0.9219
Epoch 39: val_loss improved from 0.39075 to 0.35526, saving model to best_model.h5
230/230 [==============================] - 31s 130ms/step - loss: 0.2217 - accuracy: 0.9219 - val_loss: 0.3553 - val_accuracy: 0.8971
Epoch 40/100
229/230 [============================>.] - ETA: 0s - loss: 0.2233 - accuracy: 0.9249
Epoch 40: val_loss did not improve from 0.35526
230/230 [==============================] - 31s 134ms/step - loss: 0.2238 - accuracy: 0.9246 - val_loss: 0.4069 - val_accuracy: 0.8905
Epoch 41/100
229/230 [============================>.] - ETA: 0s - loss: 0.1809 - accuracy: 0.9367
Epoch 41: val_loss did not improve from 0.35526
230/230 [==============================] - 28s 120ms/step - loss: 0.1805 - accuracy: 0.9367 - val_loss: 0.3897 - val_accuracy: 0.8967
Epoch 42/100
229/230 [============================>.] - ETA: 0s - loss: 0.1863 - accuracy: 0.9370
Epoch 42: val_loss did not improve from 0.35526
230/230 [==============================] - 28s 121ms/step - loss: 0.1862 - accuracy: 0.9369 - val_loss: 0.4940 - val_accuracy: 0.8690
Epoch 43/100
229/230 [============================>.] - ETA: 0s - loss: 0.1702 - accuracy: 0.9397
Epoch 43: val_loss did not improve from 0.35526
230/230 [==============================] - 28s 121ms/step - loss: 0.1703 - accuracy: 0.9395 - val_loss: 0.4771 - val_accuracy: 0.8914
Epoch 44/100
229/230 [============================>.] - ETA: 0s - loss: 0.1883 - accuracy: 0.9391
Epoch 44: val_loss did not improve from 0.35526
230/230 [==============================] - 28s 121ms/step - loss: 0.1887 - accuracy: 0.9389 - val_loss: 0.3675 - val_accuracy: 0.8995
Epoch 45/100
229/230 [============================>.] - ETA: 0s - loss: 0.1768 - accuracy: 0.9385
Epoch 45: val_loss did not improve from 0.35526
230/230 [==============================] - 29s 122ms/step - loss: 0.1764 - accuracy: 0.9385 - val_loss: 0.4906 - val_accuracy: 0.8852
Epoch 46/100
229/230 [============================>.] - ETA: 0s - loss: 0.1829 - accuracy: 0.9365
Epoch 46: val_loss did not improve from 0.35526
230/230 [==============================] - 28s 119ms/step - loss: 0.1833 - accuracy: 0.9365 - val_loss: 0.4830 - val_accuracy: 0.8771
Epoch 47/100
229/230 [============================>.] - ETA: 0s - loss: 0.1516 - accuracy: 0.9481
Epoch 47: val_loss did not improve from 0.35526
230/230 [==============================] - 29s 121ms/step - loss: 0.1512 - accuracy: 0.9483 - val_loss: 0.4557 - val_accuracy: 0.8871
Epoch 48/100
229/230 [============================>.] - ETA: 0s - loss: 0.1512 - accuracy: 0.9471
Epoch 48: val_loss did not improve from 0.35526
230/230 [==============================] - 28s 121ms/step - loss: 0.1512 - accuracy: 0.9469 - val_loss: 0.3762 - val_accuracy: 0.9038
Epoch 49/100
229/230 [============================>.] - ETA: 0s - loss: 0.1552 - accuracy: 0.9475
Epoch 49: val_loss did not improve from 0.35526
230/230 [==============================] - 28s 121ms/step - loss: 0.1555 - accuracy: 0.9473 - val_loss: 0.5175 - val_accuracy: 0.8752
Epoch 49: early stopping
In [12]:
# Representación del loss
mostrar_graficas(entrenamiento_modelo_final)
In [13]:
#Información del modelo
modelo_final.summary() 
Model: "model"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_1 (InputLayer)        [(None, 224, 224, 3)]     0         
                                                                 
 rescaling (Rescaling)       (None, 224, 224, 3)       0         
                                                                 
 conv2d (Conv2D)             (None, 224, 224, 32)      896       
                                                                 
 conv2d_1 (Conv2D)           (None, 224, 224, 32)      9248      
                                                                 
 max_pooling2d (MaxPooling2D  (None, 112, 112, 32)     0         
 )                                                               
                                                                 
 conv2d_2 (Conv2D)           (None, 112, 112, 64)      18496     
                                                                 
 conv2d_3 (Conv2D)           (None, 112, 112, 64)      36928     
                                                                 
 max_pooling2d_1 (MaxPooling  (None, 56, 56, 64)       0         
 2D)                                                             
                                                                 
 conv2d_4 (Conv2D)           (None, 56, 56, 128)       73856     
                                                                 
 conv2d_5 (Conv2D)           (None, 56, 56, 128)       147584    
                                                                 
 max_pooling2d_2 (MaxPooling  (None, 28, 28, 128)      0         
 2D)                                                             
                                                                 
 global_average_pooling2d (G  (None, 128)              0         
 lobalAveragePooling2D)                                          
                                                                 
 dense (Dense)               (None, 512)               66048     
                                                                 
 dropout (Dropout)           (None, 512)               0         
                                                                 
 dense_1 (Dense)             (None, 21)                10773     
                                                                 
=================================================================
Total params: 363,829
Trainable params: 363,829
Non-trainable params: 0
_________________________________________________________________
In [14]:
# Estadísticas y resultados del modelo 
test_loss, test_acc = modelo_final.evaluate(test_data)

print("\nTiempo de entrenamiento:", end_time - start_time)
print('Pérdida en el conjunto de test:', test_loss)
print('Precisión en el conjunto de test:', test_acc)
33/33 [==============================] - 6s 132ms/step - loss: 0.4912 - accuracy: 0.8695

Tiempo de entrenamiento: 1600.0847635269165
Pérdida en el conjunto de test: 0.491167813539505
Precisión en el conjunto de test: 0.869523823261261
Comentarios:

Para diseñar una red neuronal que mejore los resultados de clasificación de las redes anteriores, se propone la siguiente arquitectura: * Capa de entrada con rescalado de los datos de entrada. * Bloque extractor de características: * 2 capas convolucionales con kernel de (3,3), activación ReLU y padding 'same', seguidas de una capa de pooling de (2,2). Este bloque se repite tres veces para aumentar la profundidad de la red. * Capa global de pooling para reducir la dimensionalidad de las características extraídas. * Capa completamente conectada con 512 neuronas y activación ReLU. * Capa de dropout con una tasa del 50%. * Capa de salida con activación softmax y 21 unidades, correspondientes a las 21 clases del conjunto de datos. * Se ha utilizado la función de activación 'softmax' en la capa de salida y la pérdida 'sparse_categorical_crossentropy' en la compilación del modelo. El optimizador utilizado ha sido Adam con un learning rate de 0.0001. * Se ha entrenado el modelo durante 100 épocas utilizando EarlyStopping con una persistencia de 10 épocas, monitorizando la accuracy en el conjunto de validación, y guardando los pesos que mejor resultado hayan obtenido. Se ha monitorizado la métrica accuracy durante entrenamiento y validación. Los resultados obtenidos han sido: * El número de parámetros a entrenar en esta red propia es de 363,829. * El tiempo de entrenamiento ha sido de 26 minutos aproximadamente. * Los resultados obtenidos han sido muy buenos, con una precisión final del 86,95% sobre el conjunto de test, superando al resto de modelos planteados anteriormente.